pax_global_header00006660000000000000000000000064142260431230014507gustar00rootroot0000000000000052 comment=39eead746e18a49a8bbb108457b8879c1b7f6bce cryptacular-1.2.5/000077500000000000000000000000001422604312300140455ustar00rootroot00000000000000cryptacular-1.2.5/.gitattributes000066400000000000000000000000601422604312300167340ustar00rootroot00000000000000src/test/resources/plaintexts/*.txt text eol=lf cryptacular-1.2.5/.gitignore000066400000000000000000000000231422604312300160300ustar00rootroot00000000000000*.iml .idea target cryptacular-1.2.5/LICENSE000066400000000000000000000002471422604312300150550ustar00rootroot00000000000000This product is dual licensed under a choice of either the Apache-2.0 or the LGPL-3.0 license. See LICENSE-apache2 and LICENSE-lgpl for the full text of the licenses. cryptacular-1.2.5/LICENSE-apache2000066400000000000000000000261371422604312300163640ustar00rootroot00000000000000 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 APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] 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. cryptacular-1.2.5/LICENSE-lgpl000066400000000000000000000167251422604312300160210ustar00rootroot00000000000000 GNU LESSER GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. This version of the GNU Lesser General Public License incorporates the terms and conditions of version 3 of the GNU General Public License, supplemented by the additional permissions listed below. 0. Additional Definitions. As used herein, "this License" refers to version 3 of the GNU Lesser General Public License, and the "GNU GPL" refers to version 3 of the GNU General Public License. "The Library" refers to a covered work governed by this License, other than an Application or a Combined Work as defined below. An "Application" is any work that makes use of an interface provided by the Library, but which is not otherwise based on the Library. Defining a subclass of a class defined by the Library is deemed a mode of using an interface provided by the Library. A "Combined Work" is a work produced by combining or linking an Application with the Library. The particular version of the Library with which the Combined Work was made is also called the "Linked Version". The "Minimal Corresponding Source" for a Combined Work means the Corresponding Source for the Combined Work, excluding any source code for portions of the Combined Work that, considered in isolation, are based on the Application, and not on the Linked Version. The "Corresponding Application Code" for a Combined Work means the object code and/or source code for the Application, including any data and utility programs needed for reproducing the Combined Work from the Application, but excluding the System Libraries of the Combined Work. 1. Exception to Section 3 of the GNU GPL. You may convey a covered work under sections 3 and 4 of this License without being bound by section 3 of the GNU GPL. 2. Conveying Modified Versions. If you modify a copy of the Library, and, in your modifications, a facility refers to a function or data to be supplied by an Application that uses the facility (other than as an argument passed when the facility is invoked), then you may convey a copy of the modified version: a) under this License, provided that you make a good faith effort to ensure that, in the event an Application does not supply the function or data, the facility still operates, and performs whatever part of its purpose remains meaningful, or b) under the GNU GPL, with none of the additional permissions of this License applicable to that copy. 3. Object Code Incorporating Material from Library Header Files. The object code form of an Application may incorporate material from a header file that is part of the Library. You may convey such object code under terms of your choice, provided that, if the incorporated material is not limited to numerical parameters, data structure layouts and accessors, or small macros, inline functions and templates (ten or fewer lines in length), you do both of the following: a) Give prominent notice with each copy of the object code that the Library is used in it and that the Library and its use are covered by this License. b) Accompany the object code with a copy of the GNU GPL and this license document. 4. Combined Works. You may convey a Combined Work under terms of your choice that, taken together, effectively do not restrict modification of the portions of the Library contained in the Combined Work and reverse engineering for debugging such modifications, if you also do each of the following: a) Give prominent notice with each copy of the Combined Work that the Library is used in it and that the Library and its use are covered by this License. b) Accompany the Combined Work with a copy of the GNU GPL and this license document. c) For a Combined Work that displays copyright notices during execution, include the copyright notice for the Library among these notices, as well as a reference directing the user to the copies of the GNU GPL and this license document. d) Do one of the following: 0) Convey the Minimal Corresponding Source under the terms of this License, and the Corresponding Application Code in a form suitable for, and under terms that permit, the user to recombine or relink the Application with a modified version of the Linked Version to produce a modified Combined Work, in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source. 1) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (a) uses at run time a copy of the Library already present on the user's computer system, and (b) will operate properly with a modified version of the Library that is interface-compatible with the Linked Version. e) Provide Installation Information, but only if you would otherwise be required to provide such information under section 6 of the GNU GPL, and only to the extent that such information is necessary to install and execute a modified version of the Combined Work produced by recombining or relinking the Application with a modified version of the Linked Version. (If you use option 4d0, the Installation Information must accompany the Minimal Corresponding Source and Corresponding Application Code. If you use option 4d1, you must provide the Installation Information in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source.) 5. Combined Libraries. You may place library facilities that are a work based on the Library side by side in a single library together with other library facilities that are not Applications and are not covered by this License, and convey such a combined library under terms of your choice, if you do both of the following: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities, conveyed under the terms of this License. b) Give prominent notice with the combined library that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 6. Revised Versions of the GNU Lesser General Public License. The Free Software Foundation may publish revised and/or new versions of the GNU Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library as you received it specifies that a certain numbered version of the GNU Lesser General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that published version or of any later version published by the Free Software Foundation. If the Library as you received it does not specify a version number of the GNU Lesser General Public License, you may choose any version of the GNU Lesser General Public License ever published by the Free Software Foundation. If the Library as you received it specifies that a proxy can decide whether future versions of the GNU Lesser General Public License shall apply, that proxy's public statement of acceptance of any version is permanent authorization for you to choose that version for the Library. cryptacular-1.2.5/NOTICE000066400000000000000000000002451422604312300147520ustar00rootroot00000000000000Cryptacular Java Library Copyright (C) 2003-2022 Virginia Tech. All rights reserved. This product includes software developed at Virginia Tech (http://www.vt.edu). cryptacular-1.2.5/README.md000066400000000000000000000010161422604312300153220ustar00rootroot00000000000000# Cryptacular [![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.cryptacular/cryptacular/badge.svg?style=flat)](https://maven-badges.herokuapp.com/maven-central/org.cryptacular/cryptacular) The spectacular complement to the Bouncy Castle crypto API for Java. Cryptacular in a nutshell: * Utilities to perform common crypto operations (hash, encrypt, encode). * Stateful, thread-safe bean components. * Components to facilitate strict adherence to standards. * Comprehensive documentation and examples. cryptacular-1.2.5/pom.xml000066400000000000000000000316561422604312300153750ustar00rootroot00000000000000 4.0.0 org.cryptacular cryptacular jar 1.2.5 Cryptacular Library The spectacular complement to the Bouncy Castle crypto API for Java. http://www.cryptacular.org GitHub https://github.com/vt-middleware/cryptacular/issues cryptacular cryptacular+subscribe@googlegroups.com cryptacular+unsubscribe@googlegroups.com cryptacular@googlegroups.com http://groups.google.com/group/cryptacular Apache 2 http://www.apache.org/licenses/LICENSE-2.0.txt GNU Lesser General Public License http://www.gnu.org/licenses/lgpl-3.0.txt scm:git:git@github.com:vt-middleware/cryptacular.git scm:git:git@github.com:vt-middleware/cryptacular.git HEAD dfisher Daniel Fisher dfisher@vt.edu Virginia Tech http://www.vt.edu developer serac Marvin S. Addison serac@vt.edu Virginia Tech http://www.vt.edu developer UTF-8 UTF-8 ${basedir}/src/main/checkstyle ${basedir}/src/main/assembly 0 true 1.2.0 org.bouncycastle bcprov-jdk18on 1.71 org.testng testng 7.5 test org.apache.maven.plugins maven-enforcer-plugin 3.0.0 enforce-maven enforce [3.8.0,) org.apache.maven.plugins maven-resources-plugin 3.2.0 copy-info validate copy-resources ${basedir}/target/package-info ${basedir} false README* LICENSE* NOTICE* pom.xml copy-scripts validate copy-resources ${basedir}/target/bin bin true org.apache.maven.plugins maven-clean-plugin 3.2.0 org.apache.maven.plugins maven-deploy-plugin 3.0.0-M2 org.apache.maven.plugins maven-install-plugin 3.0.0-M1 org.apache.maven.plugins maven-site-plugin 3.11.0 org.apache.maven.plugins maven-compiler-plugin 3.10.1 true true true true -Xlint:unchecked 1.8 1.8 org.apache.maven.plugins maven-checkstyle-plugin 3.1.2 com.puppycrawl.tools checkstyle 9.3 ${checkstyle.dir}/checks.xml ${checkstyle.dir}/header.txt ${checkstyle.dir}/suppressions.xml true true plain ${project.build.directory}/checkstyle-result.txt checkstyle compile checkstyle org.apache.maven.plugins maven-surefire-plugin 2.22.2 10 surefire.testng.verbose ${testng.verbosity} com.github.siom79.japicmp japicmp-maven-plugin 0.15.7 ${project.groupId} ${project.artifactId} ${japicmp.oldVersion} jar ${project.build.directory}/${project.artifactId}-${project.version}.${project.packaging} false true ${japicmp.enabled} jar verify cmp org.apache.maven.plugins maven-javadoc-plugin 3.3.2 8 http://download.oracle.com/javase/8/docs/api Copyright © 2003-2022 Virginia Tech. All Rights Reserved.]]> javadoc package jar org.apache.maven.plugins maven-source-plugin 3.2.1 source package jar org.apache.maven.plugins maven-jar-plugin 3.2.2 ${project.build.outputDirectory}/META-INF/MANIFEST.MF jar package test-jar org.apache.felix maven-bundle-plugin 5.1.4 bundle-manifest process-classes manifest org.apache.maven.plugins maven-assembly-plugin 3.3.0 true false ${assembly.dir}/cryptacular.xml 0755 assembly package single org.apache.maven.plugins maven-release-plugin 3.0.0-M5 v@{project.version} sign-artifacts sign true org.apache.maven.plugins maven-gpg-plugin 3.0.1 sign-artifacts package sign cryptacular-1.2.5/publish-snapshot000077500000000000000000000017231422604312300173010ustar00rootroot00000000000000#!/bin/bash function user_continue() { read -p "Do you want to continue? [y/n]" -n 1 -r echo if [[ ! $REPLY =~ ^[Yy]$ ]]; then exit 1 fi } if [ "$#" -ne 1 ]; then echo "USAGE: `basename $0` " exit fi REPO_PATH="${1}" SHA=`git rev-parse --verify HEAD` echo "=================================================================" echo "BEGIN PUBLISH SNAPSHOT for revision ${SHA} at ${REPO_PATH}" echo "=================================================================" user_continue # update pom to release version mvn clean && mvn package -Dmaven.javadoc.skip=true -B -V # Clone the maven repo pushd ${REPO_PATH} git pull popd # Deploy the artifact to the maven repo mvn deploy -DskipTests -DaltDeploymentRepository=snapshot::default::file://${REPO_PATH} # Push changes to the maven repo pushd ${REPO_PATH} git add . git commit -a -m "Publish snapshot: ${SHA}" git push origin master popd echo "Successfully published SNAPSHOT artifacts for ${SHA}" cryptacular-1.2.5/release000077500000000000000000000070051422604312300154150ustar00rootroot00000000000000#!/bin/bash function user_continue() { read -p "Do you want to continue? [y/n]" -n 1 -r echo if [[ ! $REPLY =~ ^[Yy]$ ]]; then exit 1 fi } if [ "$#" -ne 5 ]; then echo "USAGE: `basename $0` " exit fi PROJECT="cryptacular" BRANCH="${1}" RELEASE_VERSION="${2}" if [[ ! "${RELEASE_VERSION}" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then echo " must be of the form 'MAJOR.MINOR.REVISION'" exit fi NEXT_VERSION="${3}" if [[ ! "${NEXT_VERSION}" =~ ^[0-9]+\.[0-9]+\.[0-9]+-SNAPSHOT$ ]]; then echo " must be of the form 'MAJOR.MINOR.REVISION-SNAPSHOT'" exit fi SONATYPE_USER="${4}" SONATYPE_PASSWORD="${5}" if [ -z $(git config --get user.signingkey) ]; then echo "Git signing must be enabled. Add user.signingkey to ~/.gitconfig" exit fi if [ $(git tag -l | grep "$RELEASE_VERSION") ]; then echo "Tag ${RELEASE_VERSION} already exists" exit fi echo "=================================================================" echo "BEGIN RELEASE" echo "PROJECT: ${PROJECT}" echo "BRANCH TO TAG: ${BRANCH}" echo "RELEASE VERSION: ${RELEASE_VERSION}" echo "NEXT VERSION: ${NEXT_VERSION}" echo "=================================================================" user_continue # update pom to release version mvn clean mvn versions:set -DnewVersion=${RELEASE_VERSION} -DgenerateBackupPoms=false echo "Updated pom to release version ${RELEASE_VERSION}" user_continue # commit pom changes git commit pom.xml -m "Update version for ${RELEASE_VERSION} release." # tag the release version git tag -s v${RELEASE_VERSION} -m "Tagging ${RELEASE_VERSION} release." echo "Tagged release ${RELEASE_VERSION}" # update pom to the next version mvn versions:set -DnewVersion=${NEXT_VERSION} -DgenerateBackupPoms=false echo "Updated pom to next version ${NEXT_VERSION}" # commit pom changes git commit pom.xml -m "Bump version to ${NEXT_VERSION}." # push commits git push origin ${BRANCH} # push release tag git push origin v${RELEASE_VERSION} # checkout the release tag git checkout v${RELEASE_VERSION} echo "Switched to the tag version ${RELEASE_VERSION}" # build the release distribution mvn -Dsign=true repository:bundle-create gpg --armor --detach-sign target/${PROJECT}-${RELEASE_VERSION}-dist.tar.gz gpg --armor --detach-sign target/${PROJECT}-${RELEASE_VERSION}-dist.zip # update the javadocs echo "Updating javadocs" user_continue git checkout gh-pages git pull origin gh-pages # remove root directory javadocs git rm -r javadocs/org javadocs/*.html javadocs/*.css javadocs/*.js javadocs/package-list # add new javadocs to root directory cp -Rp target/apidocs/ javadocs # add new javadocs to release version directory cp -Rp target/apidocs/ javadocs/${RELEASE_VERSION} git add javadocs git commit -a -m "Updated javadocs for ${RELEASE_VERSION} release." echo "Committed new javadocs" # add new binaries echo "Adding release binaries" user_continue mkdir downloads/${RELEASE_VERSION} cp target/*-dist* downloads/${RELEASE_VERSION} git add downloads/${RELEASE_VERSION} git commit -a -m "Added binaries for ${RELEASE_VERSION} release." echo "Committed new release binaries" # push changes to the server git push origin gh-pages # upload bundle jar to sonatype echo "Uploading bundle jar to sonatype" user_continue curl -i -u ${SONATYPE_USER}:${SONATYPE_PASSWORD} \ -F "file=@target/${PROJECT}-"${RELEASE_VERSION}"-bundle.jar" \ "https://oss.sonatype.org/service/local/staging/bundle_upload" echo "Finished release ${RELEASE_VERSION} for ${PROJECT}" cryptacular-1.2.5/src/000077500000000000000000000000001422604312300146345ustar00rootroot00000000000000cryptacular-1.2.5/src/main/000077500000000000000000000000001422604312300155605ustar00rootroot00000000000000cryptacular-1.2.5/src/main/assembly/000077500000000000000000000000001422604312300173775ustar00rootroot00000000000000cryptacular-1.2.5/src/main/assembly/cryptacular.xml000066400000000000000000000034371422604312300224610ustar00rootroot00000000000000 dist tar.gz zip false lib runtime *:jar target/package-info / ** true src true target jars ${project.build.finalName}*.jar true target/site/apidocs docs/apidocs true target/bin bin true *.bat *.config target/bin bin 0755 true *.bat *.config cryptacular-1.2.5/src/main/checkstyle/000077500000000000000000000000001422604312300177165ustar00rootroot00000000000000cryptacular-1.2.5/src/main/checkstyle/checks.xml000066400000000000000000000170051422604312300217030ustar00rootroot00000000000000 cryptacular-1.2.5/src/main/checkstyle/header.txt000066400000000000000000000000741422604312300217100ustar00rootroot00000000000000/\* See LICENSE for licensing and NOTICE for copyright. \*/ cryptacular-1.2.5/src/main/checkstyle/suppressions.xml000066400000000000000000000004441422604312300232170ustar00rootroot00000000000000 cryptacular-1.2.5/src/main/java/000077500000000000000000000000001422604312300165015ustar00rootroot00000000000000cryptacular-1.2.5/src/main/java/org/000077500000000000000000000000001422604312300172705ustar00rootroot00000000000000cryptacular-1.2.5/src/main/java/org/cryptacular/000077500000000000000000000000001422604312300216215ustar00rootroot00000000000000cryptacular-1.2.5/src/main/java/org/cryptacular/CiphertextHeader.java000066400000000000000000000160001422604312300257110ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular; import java.io.IOException; import java.io.InputStream; import java.nio.BufferUnderflowException; import java.nio.ByteBuffer; import java.nio.ByteOrder; import org.cryptacular.util.ByteUtil; /** * Cleartext header prepended to ciphertext providing data required for decryption. * *

Data format:

* *
     +-----+----------+-------+------------+---------+
     | Len | NonceLen | Nonce | KeyNameLen | KeyName |
     +-----+----------+-------+------------+---------+
 * 
* *

Where fields are defined as follows:

* *
    *
  • Len - Total header length in bytes (4-byte integer)
  • *
  • NonceLen - Nonce length in bytes (4-byte integer)
  • *
  • Nonce - Nonce bytes (variable length)
  • *
  • KeyNameLen (OPTIONAL) - Key name length in bytes (4-byte integer)
  • *
  • KeyName (OPTIONAL) - Key name encoded as bytes in platform-specific encoding (variable length)
  • *
* *

The last two fields are optional and provide support for multiple keys at the encryption provider. A common case * for multiple keys is key rotation; by tagging encrypted data with a key name, an old key may be retrieved by name to * decrypt outstanding data which will be subsequently re-encrypted with a new key.

* * @author Middleware Services * * @deprecated Superseded by {@link CiphertextHeaderV2} */ @Deprecated public class CiphertextHeader { /** Maximum nonce length in bytes. */ protected static final int MAX_NONCE_LEN = 255; /** Maximum key name length in bytes. */ protected static final int MAX_KEYNAME_LEN = 500; /** Header nonce field value. */ protected final byte[] nonce; /** Header key name field value. */ protected String keyName; /** Header length in bytes. */ protected int length; /** * Creates a new instance with only a nonce. * * @param nonce Nonce bytes. */ public CiphertextHeader(final byte[] nonce) { this(nonce, null); } /** * Creates a new instance with a nonce and named key. * * @param nonce Nonce bytes. * @param keyName Key name. */ public CiphertextHeader(final byte[] nonce, final String keyName) { if (nonce.length > MAX_NONCE_LEN) { throw new IllegalArgumentException("Nonce exceeds size limit in bytes (" + MAX_NONCE_LEN + ")"); } if (keyName != null) { if (ByteUtil.toBytes(keyName).length > MAX_KEYNAME_LEN) { throw new IllegalArgumentException("Key name exceeds size limit in bytes (" + MAX_KEYNAME_LEN + ")"); } } this.nonce = nonce; this.keyName = keyName; length = computeLength(); } /** * Gets the header length in bytes. * * @return Header length in bytes. */ public int getLength() { return this.length; } /** * Gets the bytes of the nonce/IV. * * @return Nonce bytes. */ public byte[] getNonce() { return this.nonce; } /** * Gets the encryption key name stored in the header. * * @return Encryption key name. */ public String getKeyName() { return this.keyName; } /** * Encodes the header into bytes. * * @return Byte representation of header. */ public byte[] encode() { final ByteBuffer bb = ByteBuffer.allocate(length); bb.order(ByteOrder.BIG_ENDIAN); bb.putInt(length); bb.putInt(nonce.length); bb.put(nonce); if (keyName != null) { final byte[] b = keyName.getBytes(); bb.putInt(b.length); bb.put(b); } return bb.array(); } /** * @return Length of this header encoded as bytes. */ protected int computeLength() { int len = 8 + nonce.length; if (keyName != null) { len += 4 + keyName.getBytes().length; } return len; } /** * Creates a header from encrypted data containing a cleartext header prepended to the start. * * @param data Encrypted data with prepended header data. * * @return Decoded header. * * @throws EncodingException when ciphertext header cannot be decoded. */ public static CiphertextHeader decode(final byte[] data) throws EncodingException { final ByteBuffer bb = ByteBuffer.wrap(data); bb.order(ByteOrder.BIG_ENDIAN); final int length = bb.getInt(); if (length < 0) { throw new EncodingException("Bad ciphertext header"); } final byte[] nonce; int nonceLen = 0; try { nonceLen = bb.getInt(); if (nonceLen > MAX_NONCE_LEN) { throw new EncodingException("Bad ciphertext header: maximum nonce length exceeded"); } nonce = new byte[nonceLen]; bb.get(nonce); } catch (IndexOutOfBoundsException | BufferUnderflowException e) { throw new EncodingException("Bad ciphertext header"); } String keyName = null; if (length > nonce.length + 8) { final byte[] b; int keyLen = 0; try { keyLen = bb.getInt(); if (keyLen > MAX_KEYNAME_LEN) { throw new EncodingException("Bad ciphertext header: maximum key length exceeded"); } b = new byte[keyLen]; bb.get(b); keyName = new String(b); } catch (IndexOutOfBoundsException | BufferUnderflowException e) { throw new EncodingException("Bad ciphertext header"); } } return new CiphertextHeader(nonce, keyName); } /** * Creates a header from encrypted data containing a cleartext header prepended to the start. * * @param input Input stream that is positioned at the start of ciphertext header data. * * @return Decoded header. * * @throws EncodingException when ciphertext header cannot be decoded. * @throws StreamException on stream IO errors. */ public static CiphertextHeader decode(final InputStream input) throws EncodingException, StreamException { final int length = ByteUtil.readInt(input); if (length < 0) { throw new EncodingException("Bad ciphertext header"); } final byte[] nonce; int nonceLen = 0; try { nonceLen = ByteUtil.readInt(input); if (nonceLen > MAX_NONCE_LEN) { throw new EncodingException("Bad ciphertext header: maximum nonce size exceeded"); } nonce = new byte[nonceLen]; input.read(nonce); } catch (ArrayIndexOutOfBoundsException e) { throw new EncodingException("Bad ciphertext header"); } catch (IOException e) { throw new StreamException(e); } String keyName = null; if (length > nonce.length + 8) { final byte[] b; int keyLen = 0; try { keyLen = ByteUtil.readInt(input); if (keyLen > MAX_KEYNAME_LEN) { throw new EncodingException("Bad ciphertext header: maximum key length exceeded"); } b = new byte[keyLen]; input.read(b); } catch (ArrayIndexOutOfBoundsException e) { throw new EncodingException("Bad ciphertext header"); } catch (IOException e) { throw new StreamException(e); } keyName = new String(b); } return new CiphertextHeader(nonce, keyName); } } cryptacular-1.2.5/src/main/java/org/cryptacular/CiphertextHeaderV2.java000066400000000000000000000232611422604312300261300ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.nio.BufferUnderflowException; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.util.function.BiConsumer; import java.util.function.Function; import javax.crypto.SecretKey; import org.bouncycastle.crypto.digests.SHA256Digest; import org.bouncycastle.crypto.macs.HMac; import org.cryptacular.util.ByteUtil; /** * Cleartext header prepended to ciphertext providing data required for decryption. * *

Data format:

* *
     +---------+---------+---+----------+-------+------+
     | Version | KeyName | 0 | NonceLen | Nonce | HMAC |
     +---------+---------+---+----------+-------+------+
     |                                                 |
     +--- 4 ---+--- x ---+ 1 +--- 1 ----+-- y --+- 32 -+
 * 
* *

Where fields are defined as follows:

* *
    *
  • Version - Header version format as a negative number (4-byte integer). Current version is -2.
  • *
  • KeyName - Symbolic key name encoded as UTF-8 bytes (variable length)
  • *
  • 0 - Null byte signifying the end of the symbolic key name
  • *
  • NonceLen - Nonce length in bytes (1-byte unsigned integer)
  • *
  • Nonce - Nonce bytes (variable length)
  • *
  • HMAC - HMAC-256 over preceding fields (32 bytes)
  • *
* *

The last two fields provide support for multiple keys at the encryption provider. A common case for multiple * keys is key rotation; by tagging encrypted data with a key name, an old key may be retrieved by name to decrypt * outstanding data which will be subsequently re-encrypted with a new key.

* * @author Middleware Services */ public class CiphertextHeaderV2 extends CiphertextHeader { /** Header version format. */ private static final int VERSION = -2; /** Size of HMAC algorithm output in bytes. */ private static final int HMAC_SIZE = 32; /** Function to resolve a key from a symbolic key name. */ private Function keyLookup; /** * Creates a new instance with a nonce and named key. * * @param nonce Nonce bytes. * @param keyName Key name. */ public CiphertextHeaderV2(final byte[] nonce, final String keyName) { super(nonce, keyName); if (keyName == null || keyName.isEmpty()) { throw new IllegalArgumentException("Key name is required"); } } /** * Sets the function to resolve keys from {@link #keyName}. * * @param keyLookup Key lookup function. */ public void setKeyLookup(final Function keyLookup) { this.keyLookup = keyLookup; } @Override public byte[] encode() { final SecretKey key = keyLookup != null ? keyLookup.apply(keyName) : null; if (key == null) { throw new IllegalStateException("Could not resolve secret key to generate header HMAC"); } return encode(key); } /** * Encodes the header into bytes. * * @param hmacKey Key used to generate header HMAC. * * @return Byte representation of header. */ public byte[] encode(final SecretKey hmacKey) { if (hmacKey == null) { throw new IllegalArgumentException("Secret key cannot be null"); } final ByteBuffer bb = ByteBuffer.allocate(length); bb.order(ByteOrder.BIG_ENDIAN); bb.putInt(VERSION); bb.put(ByteUtil.toBytes(keyName)); bb.put((byte) 0); bb.put(ByteUtil.toUnsignedByte(nonce.length)); bb.put(nonce); bb.put(hmac(bb.array(), 0, bb.limit() - HMAC_SIZE)); return bb.array(); } /** * @return Length of this header encoded as bytes. */ protected int computeLength() { return 4 + ByteUtil.toBytes(keyName).length + 2 + nonce.length + HMAC_SIZE; } /** * Creates a header from encrypted data containing a cleartext header prepended to the start. * * @param data Encrypted data with prepended header data. * @param keyLookup Function used to look up the secret key from the symbolic key name in the header. * * @return Decoded header. * * @throws EncodingException when ciphertext header cannot be decoded. */ public static CiphertextHeaderV2 decode(final byte[] data, final Function keyLookup) throws EncodingException { final ByteBuffer bb = ByteBuffer.wrap(data).order(ByteOrder.BIG_ENDIAN); return decodeInternal( ByteBuffer.wrap(data).order(ByteOrder.BIG_ENDIAN), keyLookup, ByteBuffer -> bb.getInt(), ByteBuffer -> bb.get(), (ByteBuffer, output) -> bb.get(output)); } /** * Creates a header from encrypted data containing a cleartext header prepended to the start. * * @param input Input stream that is positioned at the start of ciphertext header data. * @param keyLookup Function used to look up the secret key from the symbolic key name in the header. * * @return Decoded header. * * @throws EncodingException when ciphertext header cannot be decoded. * @throws StreamException on stream IO errors. */ public static CiphertextHeaderV2 decode(final InputStream input, final Function keyLookup) throws EncodingException, StreamException { return decodeInternal( input, keyLookup, ByteUtil::readInt, CiphertextHeaderV2::readByte, CiphertextHeaderV2::readInto); } /** * Internal header decoding routine. * * @param Type of input source. * @param source Source of header data (input stream or byte buffer). * @param keyLookup Function to look up key from symbolic key name in header. * @param readIntFn Function that produces a 4-byte integer from the input source. * @param readByteFn Function that produces a byte from the input source. * @param readBytesConsumer Function that fills a byte array from the input source. * * @return Decoded header. */ private static CiphertextHeaderV2 decodeInternal( final T source, final Function keyLookup, final Function readIntFn, final Function readByteFn, final BiConsumer readBytesConsumer) { final SecretKey key; final String keyName; final byte[] nonce; final byte[] hmac; try { final int version = readIntFn.apply(source); if (version != VERSION) { throw new EncodingException("Unsupported ciphertext header version"); } final ByteArrayOutputStream out = new ByteArrayOutputStream(100); byte b = 0; int count = 0; while ((b = readByteFn.apply(source)) != 0) { out.write(b); if (out.size() > MAX_KEYNAME_LEN) { throw new EncodingException("Bad ciphertext header: maximum nonce length exceeded"); } count++; } keyName = ByteUtil.toString(out.toByteArray(), 0, count); key = keyLookup.apply(keyName); if (key == null) { throw new IllegalStateException("Symbolic key name mentioned in header was not found"); } final int nonceLen = ByteUtil.toInt(readByteFn.apply(source)); nonce = new byte[nonceLen]; readBytesConsumer.accept(source, nonce); hmac = new byte[HMAC_SIZE]; readBytesConsumer.accept(source, hmac); } catch (IndexOutOfBoundsException | BufferUnderflowException e) { throw new EncodingException("Bad ciphertext header"); } final CiphertextHeaderV2 header = new CiphertextHeaderV2(nonce, keyName); final byte[] encoded = header.encode(key); if (!arraysEqual(hmac, 0, encoded, encoded.length - HMAC_SIZE, HMAC_SIZE)) { throw new EncodingException("Ciphertext header HMAC verification failed"); } header.setKeyLookup(keyLookup); return header; } /** * Generates an HMAC-256 over the given input byte array. * * @param input Input bytes. * @param offset Starting position in input byte array. * @param length Number of bytes in input to consume. * * @return HMAC as byte array. */ private static byte[] hmac(final byte[] input, final int offset, final int length) { final HMac hmac = new HMac(new SHA256Digest()); final byte[] output = new byte[HMAC_SIZE]; hmac.update(input, offset, length); hmac.doFinal(output, 0); return output; } /** * Read output.length bytes from the input stream into the output buffer. * * @param input Input stream. * @param output Output buffer. * * @throws StreamException on stream IO errors. */ private static void readInto(final InputStream input, final byte[] output) { try { input.read(output); } catch (IOException e) { throw new StreamException(e); } } /** * Read a single byte from the input stream. * * @param input Input stream. * * @return Byte read from input stream. */ private static byte readByte(final InputStream input) { try { return (byte) input.read(); } catch (IOException e) { throw new StreamException(e); } } /** * Determines if two byte array ranges are equal bytewise. * * @param a First array to compare. * @param aOff Offset into first array. * @param b Second array to compare. * @param bOff Offset into second array. * @param length Number of bytes to compare. * * @return True if every byte in the given range is equal, false otherwise. */ private static boolean arraysEqual(final byte[] a, final int aOff, final byte[] b, final int bOff, final int length) { if (length + aOff > a.length || length + bOff > b.length) { return false; } for (int i = 0; i < length; i++) { if (a[i + aOff] != b[i + bOff]) { return false; } } return true; } } cryptacular-1.2.5/src/main/java/org/cryptacular/CryptoException.java000066400000000000000000000013361422604312300256260ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular; /** * Runtime error describing a generic cryptographic problem (e.g. bad padding, unsupported cipher). * * @author Middleware Services */ public class CryptoException extends RuntimeException { /** * Creates a new instance with the given error message. * * @param message Error message. */ public CryptoException(final String message) { super(message); } /** * Creates a new instance with the given error message and cause. * * @param message Error message. * @param cause Error cause. */ public CryptoException(final String message, final Throwable cause) { super(message, cause); } } cryptacular-1.2.5/src/main/java/org/cryptacular/EncodingException.java000066400000000000000000000013641422604312300260750ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular; /** * Runtime error describing an encoding problem of a cryptographic primitive (e.g. private key, X.509 certificate). * * @author Middleware Services */ public class EncodingException extends RuntimeException { /** * Creates a new instance with the given error message. * * @param message Error message. */ public EncodingException(final String message) { super(message); } /** * Creates a new instance with the given error message and cause. * * @param message Error message. * @param cause Error cause. */ public EncodingException(final String message, final Throwable cause) { super(message, cause); } } cryptacular-1.2.5/src/main/java/org/cryptacular/SaltedHash.java000066400000000000000000000063401422604312300245070ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular; import org.cryptacular.codec.Encoder; import org.cryptacular.util.CodecUtil; /** * Container for the output of a salted hash operation that includes both the digest output and salt value. * * @author Middleware Services */ public class SaltedHash { /** Digest output. */ private final byte[] hash; /** Salt value. */ private final byte[] salt; /** * Creates a new instance with digest and salt data. * * @param hash Digest output. * @param salt Salt value used to compute salt. */ public SaltedHash(final byte[] hash, final byte[] salt) { this.hash = hash; this.salt = salt; } /** * Creates a new instance from byte input that contains the concatenation of digest output and salt. * * @param hashWithSalt Concatenation of hash and salt. * @param digestLength Number of bytes in digest output. * @param toEnd True if salt is appended to end of hash, false if salt is prepended to hash. */ public SaltedHash(final byte[] hashWithSalt, final int digestLength, final boolean toEnd) { this.hash = new byte[digestLength]; this.salt = new byte[hashWithSalt.length - digestLength]; if (toEnd) { System.arraycopy(hashWithSalt, 0, hash, 0, hash.length); System.arraycopy(hashWithSalt, hash.length, salt, 0, salt.length); } else { System.arraycopy(hashWithSalt, 0, salt, 0, salt.length); System.arraycopy(hashWithSalt, salt.length, hash, 0, hash.length); } } /** @return Digest output. */ public byte[] getHash() { return hash; } /** @return Salt value. */ public byte[] getSalt() { return salt; } /** * Gets N bytes of salt. * * @param n Number of bytes of salt; must be less than or equal to salt size. * * @return First N bytes of salt. */ public byte[] getSalt(final int n) { if (n > salt.length) { throw new IllegalArgumentException("Requested size exceeded length: " + n + ">" + salt.length); } final byte[] bytes = new byte[n]; System.arraycopy(salt, 0, bytes, 0, n); return bytes; } /** * Gets an encoded string of the concatenation of digest output and salt. * * @param toEnd True to append salt to end of hash, false to prefix hash with salt. * @param encoder Encodes concatenated bytes to a string. * * @return Salt concatenated to hash encoded as a string. */ public String concatenateSalt(final boolean toEnd, final Encoder encoder) { return CodecUtil.encode(encoder, concatenateSalt(toEnd)); } /** * Gets a byte array containing the concatenation of digest output and salt. * * @param toEnd True to append salt to end of hash, false to prefix hash with salt. * * @return Salt concatenated to hash. */ public byte[] concatenateSalt(final boolean toEnd) { final byte[] output = new byte[hash.length + salt.length]; if (toEnd) { System.arraycopy(hash, 0, output, 0, hash.length); System.arraycopy(salt, 0, output, hash.length, salt.length); } else { System.arraycopy(salt, 0, output, 0, salt.length); System.arraycopy(hash, 0, output, salt.length, hash.length); } return output; } } cryptacular-1.2.5/src/main/java/org/cryptacular/StreamException.java000066400000000000000000000013171422604312300256000ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular; import java.io.IOException; /** * Runtime exception thrown on stream IO errors. Effectively a runtime equivalent of {@link java.io.IOException}. * * @author Middleware Services */ public class StreamException extends RuntimeException { /** * Creates a new instance with the given error message. * * @param message Error message. */ public StreamException(final String message) { super(message); } /** * Creates a new instance with causing IO exception. * * @param cause IO exception to wrap. */ public StreamException(final IOException cause) { super("IO error", cause); } } cryptacular-1.2.5/src/main/java/org/cryptacular/adapter/000077500000000000000000000000001422604312300232415ustar00rootroot00000000000000cryptacular-1.2.5/src/main/java/org/cryptacular/adapter/AEADBlockCipherAdapter.java000066400000000000000000000035171422604312300302130ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.adapter; import org.bouncycastle.crypto.CipherParameters; import org.bouncycastle.crypto.InvalidCipherTextException; import org.bouncycastle.crypto.modes.AEADBlockCipher; import org.cryptacular.CryptoException; /** * Adapts a {@link AEADBlockCipherAdapter}. * * @author Middleware Services */ public class AEADBlockCipherAdapter implements BlockCipherAdapter { /** All methods delegate to this instance. */ private final AEADBlockCipher cipherDelegate; /** * Creates a new instance that delegates to the given cipher. * * @param delegate Adapted cipher. */ public AEADBlockCipherAdapter(final AEADBlockCipher delegate) { cipherDelegate = delegate; } @Override public int getOutputSize(final int len) { return cipherDelegate.getOutputSize(len); } @Override public void init(final boolean forEncryption, final CipherParameters params) throws CryptoException { try { cipherDelegate.init(forEncryption, params); } catch (RuntimeException e) { throw new CryptoException("Cipher initialization error", e); } } @Override public int processBytes(final byte[] in, final int inOff, final int len, final byte[] out, final int outOff) throws CryptoException { try { return cipherDelegate.processBytes(in, inOff, len, out, outOff); } catch (RuntimeException e) { throw new CryptoException("Cipher processing error", e); } } @Override public int doFinal(final byte[] out, final int outOff) throws CryptoException { try { return cipherDelegate.doFinal(out, outOff); } catch (InvalidCipherTextException e) { throw new CryptoException("Error finalizing cipher", e); } } @Override public void reset() { cipherDelegate.reset(); } } cryptacular-1.2.5/src/main/java/org/cryptacular/adapter/AbstractWrappedDSAKey.java000066400000000000000000000023371422604312300302000ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.adapter; import java.math.BigInteger; import java.security.interfaces.DSAParams; import org.bouncycastle.crypto.params.DSAKeyParameters; /** * Base class for DSA wrapped keys. * * @param DSA key parameters type. * * @author Middleware Services */ public abstract class AbstractWrappedDSAKey extends AbstractWrappedKey { /** DSA algorithm name. */ private static final String ALGORITHM = "DSA"; /** * Creates a new instance that wraps the given key. * * @param wrappedKey Key to wrap. */ public AbstractWrappedDSAKey(final T wrappedKey) { super(wrappedKey); } /** @return DSA key parameters. */ public DSAParams getParams() { return new DSAParams() { @Override public BigInteger getP() { return delegate.getParameters().getP(); } @Override public BigInteger getQ() { return delegate.getParameters().getQ(); } @Override public BigInteger getG() { return delegate.getParameters().getG(); } }; } @Override public String getAlgorithm() { return ALGORITHM; } } cryptacular-1.2.5/src/main/java/org/cryptacular/adapter/AbstractWrappedECKey.java000066400000000000000000000025621422604312300300600ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.adapter; import java.security.spec.ECParameterSpec; import java.security.spec.ECPoint; import org.bouncycastle.crypto.params.ECDomainParameters; import org.bouncycastle.crypto.params.ECKeyParameters; import org.bouncycastle.jcajce.provider.asymmetric.util.EC5Util; /** * Base class for wrapped EC keys. * * @param EC key parameters type. * * @author Middleware Services */ public abstract class AbstractWrappedECKey extends AbstractWrappedKey { /** Elliptic curve algorithm name. */ private static final String ALGORITHM = "EC"; /** * Creates a new instance that wraps the given key. * * @param wrappedKey Key to wrap. */ public AbstractWrappedECKey(final T wrappedKey) { super(wrappedKey); } /** @return EC domain parameters. */ public ECParameterSpec getParams() { final ECDomainParameters params = delegate.getParameters(); return new ECParameterSpec( EC5Util.convertCurve(params.getCurve(), params.getSeed()), new ECPoint( params.getG().normalize().getXCoord().toBigInteger(), params.getG().normalize().getYCoord().toBigInteger()), params.getN(), params.getH().intValue()); } @Override public String getAlgorithm() { return ALGORITHM; } } cryptacular-1.2.5/src/main/java/org/cryptacular/adapter/AbstractWrappedKey.java000066400000000000000000000037241422604312300276510ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.adapter; import java.io.IOException; import java.security.Key; import org.bouncycastle.crypto.params.AsymmetricKeyParameter; import org.bouncycastle.crypto.util.PrivateKeyInfoFactory; import org.bouncycastle.crypto.util.SubjectPublicKeyInfoFactory; import org.cryptacular.EncodingException; /** * JCE/JDK key base class that wraps a BC native private key. * * @param Asymmetric key parameters type wrapped by this class. * * @author Middleware Services */ public abstract class AbstractWrappedKey implements Key { /** PKCS#8 format identifier used with private keys. */ public static final String PKCS8_FORMAT = "PKCS#8"; /** X.509 format identifier used with private keys. */ public static final String X509_FORMAT = "X.509"; /** Wrapped key. */ protected final T delegate; /** * Creates a new instance that wraps the given BC key. * * @param wrappedKey BC key to wrap. */ public AbstractWrappedKey(final T wrappedKey) { if (wrappedKey == null) { throw new IllegalArgumentException("Wrapped key cannot be null."); } delegate = wrappedKey; } /** @return {@value #PKCS8_FORMAT} in the case of a private key, otherwise {@link #X509_FORMAT}. */ @Override public String getFormat() { if (delegate.isPrivate()) { return PKCS8_FORMAT; } return X509_FORMAT; } /** * @return Encoded PrivateKeyInfo structure in the case of a private key, otherwise an encoded SubjectPublicKeyInfo * structure. */ @Override public byte[] getEncoded() { try { if (delegate.isPrivate()) { return PrivateKeyInfoFactory.createPrivateKeyInfo(delegate).getEncoded(); } return SubjectPublicKeyInfoFactory.createSubjectPublicKeyInfo(delegate).getEncoded(); } catch (IOException e) { throw new EncodingException("Key encoding error", e); } } } cryptacular-1.2.5/src/main/java/org/cryptacular/adapter/AbstractWrappedRSAKey.java000066400000000000000000000015751422604312300302210ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.adapter; import java.math.BigInteger; import org.bouncycastle.crypto.params.RSAKeyParameters; /** * Base class for RSA wrapped keys. * * @param RSA key parameters type handled by this class. * * @author Middleware Services */ public abstract class AbstractWrappedRSAKey extends AbstractWrappedKey { /** RSA algorithm name. */ private static final String ALGORITHM = "RSA"; /** * Creates a new instance that wraps the given key. * * @param wrappedKey Key to wrap. */ public AbstractWrappedRSAKey(final T wrappedKey) { super(wrappedKey); } /** @return Gets the RSA modulus. */ public BigInteger getModulus() { return delegate.getModulus(); } @Override public String getAlgorithm() { return ALGORITHM; } } cryptacular-1.2.5/src/main/java/org/cryptacular/adapter/BlockCipherAdapter.java000066400000000000000000000016731422604312300276010ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.adapter; import org.cryptacular.CryptoException; /** * Adapter for all block cipher types. * * @author Middleware Services */ public interface BlockCipherAdapter extends CipherAdapter { /** * Gets the size of the output buffer required to hold the output of an input buffer of the given size. * * @param len Length of input buffer. * * @return Size of output buffer. */ int getOutputSize(int len); /** * Finish the encryption/decryption operation (e.g. apply padding). * * @param out Output buffer to receive final processing output. * @param outOff Offset into output buffer where processed data should start. * * @return Number of bytes written to output buffer. * * @throws CryptoException on underlying cipher finalization errors. */ int doFinal(byte[] out, int outOff) throws CryptoException; } cryptacular-1.2.5/src/main/java/org/cryptacular/adapter/BufferedBlockCipherAdapter.java000066400000000000000000000035321422604312300312400ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.adapter; import org.bouncycastle.crypto.BufferedBlockCipher; import org.bouncycastle.crypto.CipherParameters; import org.bouncycastle.crypto.InvalidCipherTextException; import org.cryptacular.CryptoException; /** * Adapts a {@link BufferedBlockCipher}. * * @author Middleware Services */ public class BufferedBlockCipherAdapter implements BlockCipherAdapter { /** All methods delegate to this instance. */ private final BufferedBlockCipher cipherDelegate; /** * Creates a new instance that delegates to the given cipher. * * @param delegate Adapted cipher. */ public BufferedBlockCipherAdapter(final BufferedBlockCipher delegate) { cipherDelegate = delegate; } @Override public int getOutputSize(final int len) { return cipherDelegate.getOutputSize(len); } @Override public void init(final boolean forEncryption, final CipherParameters params) throws CryptoException { try { cipherDelegate.init(forEncryption, params); } catch (RuntimeException e) { throw new CryptoException("Cipher initialization error", e); } } @Override public int processBytes(final byte[] in, final int inOff, final int len, final byte[] out, final int outOff) throws CryptoException { try { return cipherDelegate.processBytes(in, inOff, len, out, outOff); } catch (RuntimeException e) { throw new CryptoException("Cipher processing error", e); } } @Override public int doFinal(final byte[] out, final int outOff) throws CryptoException { try { return cipherDelegate.doFinal(out, outOff); } catch (InvalidCipherTextException e) { throw new CryptoException("Error finalizing cipher", e); } } @Override public void reset() { cipherDelegate.reset(); } } cryptacular-1.2.5/src/main/java/org/cryptacular/adapter/CipherAdapter.java000066400000000000000000000026521422604312300266240ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.adapter; import org.bouncycastle.crypto.CipherParameters; import org.cryptacular.CryptoException; /** * Provides a consistent interface for cipher operations against dissimilar BC cipher types. * * @author Middleware Services */ public interface CipherAdapter { /** * Initialize the underlying cipher. * * @param forEncryption True for encryption mode, false for decryption mode. * @param params Cipher initialization parameters. * * @throws CryptoException on underlying cipher initialization errors. */ void init(boolean forEncryption, CipherParameters params) throws CryptoException; /** * Process an array of bytes, producing output if necessary. * * @param in Input data. * @param inOff Offset at which the input data starts. * @param len The number of bytes in the input data to process. * @param out Array to receive any data produced by cipher. * @param outOff Offset into output array. * * @return The number of bytes produced by the cipher. * * @throws CryptoException on underlying cipher data handling errors. */ int processBytes(byte[] in, int inOff, int len, byte[] out, int outOff) throws CryptoException; /** * Reset the cipher. After resetting the cipher is in the same state as it was after the last init (if there was one). */ void reset(); } cryptacular-1.2.5/src/main/java/org/cryptacular/adapter/Converter.java000066400000000000000000000050471422604312300260610ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.adapter; import java.security.PrivateKey; import java.security.PublicKey; import org.bouncycastle.crypto.params.AsymmetricKeyParameter; import org.bouncycastle.crypto.params.DSAPrivateKeyParameters; import org.bouncycastle.crypto.params.DSAPublicKeyParameters; import org.bouncycastle.crypto.params.ECPrivateKeyParameters; import org.bouncycastle.crypto.params.ECPublicKeyParameters; import org.bouncycastle.crypto.params.RSAKeyParameters; import org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters; /** * Static factory with methods to convert from BC type to the corresponding JCE type. * * @author Middleware Services */ public final class Converter { /** Private constructor of utility class. */ private Converter() {} /** * Produces a {@link PrivateKey} from a BC private key type. * * @param bcKey BC private key. * * @return JCE private key. */ public static PrivateKey convertPrivateKey(final AsymmetricKeyParameter bcKey) { if (!bcKey.isPrivate()) { throw new IllegalArgumentException("AsymmetricKeyParameter is not a private key: " + bcKey); } final PrivateKey key; if (bcKey instanceof DSAPrivateKeyParameters) { key = new WrappedDSAPrivateKey((DSAPrivateKeyParameters) bcKey); } else if (bcKey instanceof ECPrivateKeyParameters) { key = new WrappedECPrivateKey((ECPrivateKeyParameters) bcKey); } else if (bcKey instanceof RSAPrivateCrtKeyParameters) { key = new WrappedRSAPrivateCrtKey((RSAPrivateCrtKeyParameters) bcKey); } else { throw new IllegalArgumentException("Unsupported private key " + bcKey); } return key; } /** * Produces a {@link PublicKey} from a BC public key type. * * @param bcKey BC public key. * * @return JCE public key. */ public static PublicKey convertPublicKey(final AsymmetricKeyParameter bcKey) { if (bcKey.isPrivate()) { throw new IllegalArgumentException("AsymmetricKeyParameter is not a public key: " + bcKey); } final PublicKey key; if (bcKey instanceof DSAPublicKeyParameters) { key = new WrappedDSAPublicKey((DSAPublicKeyParameters) bcKey); } else if (bcKey instanceof ECPublicKeyParameters) { key = new WrappedECPublicKey((ECPublicKeyParameters) bcKey); } else if (bcKey instanceof RSAKeyParameters) { key = new WrappedRSAPublicKey((RSAKeyParameters) bcKey); } else { throw new IllegalArgumentException("Unsupported public key " + bcKey); } return key; } } cryptacular-1.2.5/src/main/java/org/cryptacular/adapter/WrappedDSAPrivateKey.java000066400000000000000000000014631422604312300300460ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.adapter; import java.math.BigInteger; import java.security.interfaces.DSAPrivateKey; import org.bouncycastle.crypto.params.DSAPrivateKeyParameters; /** * JCE/JDK DSA private key that wraps the corresponding BC DSA private key type, {@link DSAPrivateKeyParameters}. * * @author Middleware Services */ public class WrappedDSAPrivateKey extends AbstractWrappedDSAKey implements DSAPrivateKey { /** * Creates a new instance that wraps the given BC DSA private key. * * @param parameters BC DSA private key. */ public WrappedDSAPrivateKey(final DSAPrivateKeyParameters parameters) { super(parameters); } @Override public BigInteger getX() { return delegate.getX(); } } cryptacular-1.2.5/src/main/java/org/cryptacular/adapter/WrappedDSAPublicKey.java000066400000000000000000000014301422604312300276440ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.adapter; import java.math.BigInteger; import java.security.interfaces.DSAPublicKey; import org.bouncycastle.crypto.params.DSAPublicKeyParameters; /** * JCE/JDK DSA public key that wraps the corresponding BC DSA public key type, {@link DSAPublicKeyParameters}. * * @author Middleware Services */ public class WrappedDSAPublicKey extends AbstractWrappedDSAKey implements DSAPublicKey { /** * Creates a new instance that wraps the given key. * * @param wrappedKey DSA key to wrap. */ public WrappedDSAPublicKey(final DSAPublicKeyParameters wrappedKey) { super(wrappedKey); } @Override public BigInteger getY() { return delegate.getY(); } } cryptacular-1.2.5/src/main/java/org/cryptacular/adapter/WrappedECPrivateKey.java000066400000000000000000000014251422604312300277240ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.adapter; import java.math.BigInteger; import java.security.interfaces.ECPrivateKey; import org.bouncycastle.crypto.params.ECPrivateKeyParameters; /** * JCE/JDK EC private key that wraps the corresponding BC EC private key type, {@link ECPrivateKeyParameters}. * * @author Middleware Services */ public class WrappedECPrivateKey extends AbstractWrappedECKey implements ECPrivateKey { /** * Creates a new instance that wraps the given key. * * @param wrappedKey EC key to wrap. */ public WrappedECPrivateKey(final ECPrivateKeyParameters wrappedKey) { super(wrappedKey); } @Override public BigInteger getS() { return delegate.getD(); } } cryptacular-1.2.5/src/main/java/org/cryptacular/adapter/WrappedECPublicKey.java000066400000000000000000000016221422604312300275270ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.adapter; import java.security.interfaces.ECPublicKey; import java.security.spec.ECPoint; import org.bouncycastle.crypto.params.ECPublicKeyParameters; /** * JCE/JDK EC public key that wraps the corresponding BC EC public key type, {@link ECPublicKeyParameters}. * * @author Middleware Services */ public class WrappedECPublicKey extends AbstractWrappedECKey implements ECPublicKey { /** * Creates a new instance that wraps the given key. * * @param wrappedKey EC key to wrap. */ public WrappedECPublicKey(final ECPublicKeyParameters wrappedKey) { super(wrappedKey); } @Override public ECPoint getW() { return new ECPoint( delegate.getQ().normalize().getXCoord().toBigInteger(), delegate.getQ().normalize().getYCoord().toBigInteger()); } } cryptacular-1.2.5/src/main/java/org/cryptacular/adapter/WrappedRSAPrivateCrtKey.java000066400000000000000000000026201422604312300305310ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.adapter; import java.math.BigInteger; import java.security.interfaces.RSAPrivateCrtKey; import org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters; /** * JCE/JDK RSA private key that wraps the corresponding BC RSA private key type, {@link RSAPrivateCrtKeyParameters}. * * @author Middleware Services */ public class WrappedRSAPrivateCrtKey extends AbstractWrappedRSAKey implements RSAPrivateCrtKey { /** * Creates a new instance that wraps the given BC RSA private key. * * @param parameters BC RSA private (certificate) key. */ public WrappedRSAPrivateCrtKey(final RSAPrivateCrtKeyParameters parameters) { super(parameters); } @Override public BigInteger getPublicExponent() { return delegate.getPublicExponent(); } @Override public BigInteger getPrimeP() { return delegate.getP(); } @Override public BigInteger getPrimeQ() { return delegate.getQ(); } @Override public BigInteger getPrimeExponentP() { return delegate.getDP(); } @Override public BigInteger getPrimeExponentQ() { return delegate.getDQ(); } @Override public BigInteger getCrtCoefficient() { return delegate.getQInv(); } @Override public BigInteger getPrivateExponent() { return delegate.getExponent(); } } cryptacular-1.2.5/src/main/java/org/cryptacular/adapter/WrappedRSAPublicKey.java000066400000000000000000000014231422604312300276640ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.adapter; import java.math.BigInteger; import java.security.interfaces.RSAPublicKey; import org.bouncycastle.crypto.params.RSAKeyParameters; /** * JCE/JDK RSA public key that wraps the corresponding BC RSA public key type, {@link RSAKeyParameters}. * * @author Middleware Services */ public class WrappedRSAPublicKey extends AbstractWrappedRSAKey implements RSAPublicKey { /** * Creates a new instance that wraps the given key. * * @param wrappedKey RSA key to wrap. */ public WrappedRSAPublicKey(final RSAKeyParameters wrappedKey) { super(wrappedKey); } @Override public BigInteger getPublicExponent() { return delegate.getExponent(); } } cryptacular-1.2.5/src/main/java/org/cryptacular/asn/000077500000000000000000000000001422604312300224025ustar00rootroot00000000000000cryptacular-1.2.5/src/main/java/org/cryptacular/asn/ASN1Decoder.java000066400000000000000000000012501422604312300252330ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.asn; import org.cryptacular.EncodingException; /** * Strategy interface for converting encoded ASN.1 bytes to an object. * * @param Type of object to produce on decode. * * @author Middleware Services */ public interface ASN1Decoder { /** * Produces an object from an encoded representation. * * @param encoded ASN.1 encoded data. * @param args Additional data required to perform decoding. * * @return Decoded object. * * @throws EncodingException on encoding errors. */ T decode(byte[] encoded, Object... args) throws EncodingException; } cryptacular-1.2.5/src/main/java/org/cryptacular/asn/AbstractPrivateKeyDecoder.java000066400000000000000000000036771422604312300303170ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.asn; import org.cryptacular.EncodingException; import org.cryptacular.util.PemUtil; /** * Base class for all private key decoders. * * @param Type produced by decode operation. * * @author Middleware Services */ public abstract class AbstractPrivateKeyDecoder implements ASN1Decoder { @Override public T decode(final byte[] encoded, final Object... args) throws EncodingException { try { final byte[] asn1Bytes; if (args != null && args.length > 0 && args[0] instanceof char[]) { asn1Bytes = decryptKey(encoded, (char[]) args[0]); } else { asn1Bytes = tryConvertPem(encoded); } return decodeASN1(asn1Bytes); } catch (EncodingException e) { throw e; } catch (RuntimeException e) { throw new EncodingException("Key encoding error", e); } } /** * Tests the given encoded input and converts it to PEM if it is detected, stripping out any header/footer data in the * process. * * @param input Encoded data that may be PEM encoded. * * @return Decoded data if PEM encoding detected, otherwise original data. */ protected byte[] tryConvertPem(final byte[] input) { if (PemUtil.isPem(input)) { return PemUtil.decode(input); } return input; } /** * Decrypts an encrypted key in either PKCS#8 or OpenSSL "traditional" format. Both PEM and DER encodings are * supported. * * @param encrypted Encoded encrypted key data. * @param password Password to decrypt key. * * @return Decrypted key. */ protected abstract byte[] decryptKey(byte[] encrypted, char[] password); /** * Decodes the given raw ASN.1 encoded data into a private key of the type supported by this class. * * @param encoded Encoded ASN.1 data. * * @return Private key object. */ protected abstract T decodeASN1(byte[] encoded); } cryptacular-1.2.5/src/main/java/org/cryptacular/asn/OpenSSLPrivateKeyDecoder.java000066400000000000000000000127601422604312300300300ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.asn; import java.math.BigInteger; import org.bouncycastle.asn1.ASN1InputStream; import org.bouncycastle.asn1.ASN1Integer; import org.bouncycastle.asn1.ASN1Object; import org.bouncycastle.asn1.ASN1ObjectIdentifier; import org.bouncycastle.asn1.ASN1OctetString; import org.bouncycastle.asn1.ASN1Sequence; import org.bouncycastle.asn1.ASN1TaggedObject; import org.bouncycastle.asn1.x9.X9ECParameters; import org.bouncycastle.crypto.params.AsymmetricKeyParameter; import org.bouncycastle.crypto.params.DSAParameters; import org.bouncycastle.crypto.params.DSAPrivateKeyParameters; import org.bouncycastle.crypto.params.ECDomainParameters; import org.bouncycastle.crypto.params.ECPrivateKeyParameters; import org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters; import org.bouncycastle.jcajce.provider.asymmetric.util.ECUtil; import org.cryptacular.EncodingException; import org.cryptacular.pbe.OpenSSLAlgorithm; import org.cryptacular.pbe.OpenSSLEncryptionScheme; import org.cryptacular.util.ByteUtil; import org.cryptacular.util.CodecUtil; import org.cryptacular.util.PemUtil; /** * Decrypts PEM-encoded OpenSSL "traditional" format private keys. * * @author Middleware Services */ public class OpenSSLPrivateKeyDecoder extends AbstractPrivateKeyDecoder { @Override protected byte[] decryptKey(final byte[] encrypted, final char[] password) { final String pem = new String(encrypted, ByteUtil.ASCII_CHARSET); final int start = pem.indexOf(PemUtil.DEK_INFO); final int eol = pem.indexOf('\n', start); final String[] dekInfo = pem.substring(start + 10, eol).split(","); final String alg = dekInfo[0]; final byte[] iv = CodecUtil.hex(dekInfo[1]); final byte[] bytes = PemUtil.decode(encrypted); return new OpenSSLEncryptionScheme(OpenSSLAlgorithm.fromAlgorithmId(alg), iv, password).decrypt(bytes); } @Override protected AsymmetricKeyParameter decodeASN1(final byte[] encoded) { final ASN1InputStream stream = new ASN1InputStream(encoded); final ASN1Object o; try { o = stream.readObject(); } catch (Exception e) { throw new EncodingException("Invalid encoded key", e); } final AsymmetricKeyParameter key; if (o instanceof ASN1ObjectIdentifier) { // EC private key with named curve in the default OpenSSL format emitted // by openssl ecparam -name xxxx -genkey try { key = parseECPrivateKey(ASN1Sequence.getInstance(stream.readObject())); } catch (Exception e) { throw new EncodingException("Invalid encoded key", e); } } else { // OpenSSL "traditional" format is an ASN.1 sequence of key parameters // Detect key type based on number and types of parameters: // RSA -> {version, mod, pubExp, privExp, prime1, prime2, exp1, exp2, c} // DSA -> {version, p, q, g, pubExp, privExp} // EC -> {version, privateKey, parameters, publicKey} final ASN1Sequence sequence = ASN1Sequence.getInstance(o); if (sequence.size() == 9) { // RSA private certificate key key = new RSAPrivateCrtKeyParameters( ASN1Integer.getInstance(sequence.getObjectAt(1)).getValue(), ASN1Integer.getInstance(sequence.getObjectAt(2)).getValue(), ASN1Integer.getInstance(sequence.getObjectAt(3)).getValue(), ASN1Integer.getInstance(sequence.getObjectAt(4)).getValue(), ASN1Integer.getInstance(sequence.getObjectAt(5)).getValue(), ASN1Integer.getInstance(sequence.getObjectAt(6)).getValue(), ASN1Integer.getInstance(sequence.getObjectAt(7)).getValue(), ASN1Integer.getInstance(sequence.getObjectAt(8)).getValue()); } else if (sequence.size() == 6) { // DSA private key key = new DSAPrivateKeyParameters( ASN1Integer.getInstance(sequence.getObjectAt(5)).getValue(), new DSAParameters( ASN1Integer.getInstance(sequence.getObjectAt(1)).getValue(), ASN1Integer.getInstance(sequence.getObjectAt(2)).getValue(), ASN1Integer.getInstance(sequence.getObjectAt(3)).getValue())); } else if (sequence.size() == 4) { // EC private key with explicit curve key = parseECPrivateKey(sequence); } else { throw new EncodingException("Invalid OpenSSL traditional private key format."); } } return key; } /** * Parses an EC private key as defined in RFC 5915. *
   *      ECPrivateKey ::= SEQUENCE {
   *        version        INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1),
   *        privateKey     OCTET STRING,
   *        parameters [0] ECParameters {{ NamedCurve }} OPTIONAL,
   *        publicKey  [1] BIT STRING OPTIONAL
   *      }
   * 
* * @param seq ASN1 sequence to parse * * @return EC private key */ private ECPrivateKeyParameters parseECPrivateKey(final ASN1Sequence seq) { final ASN1TaggedObject asn1Params = ASN1TaggedObject.getInstance(seq.getObjectAt(2)); final X9ECParameters params; if (asn1Params.getObject() instanceof ASN1ObjectIdentifier) { params = ECUtil.getNamedCurveByOid(ASN1ObjectIdentifier.getInstance(asn1Params.getObject())); } else { params = X9ECParameters.getInstance(asn1Params.getObject()); } return new ECPrivateKeyParameters( new BigInteger(1, ASN1OctetString.getInstance(seq.getObjectAt(1)).getOctets()), new ECDomainParameters(params.getCurve(), params.getG(), params.getN(), params.getH(), params.getSeed())); } } cryptacular-1.2.5/src/main/java/org/cryptacular/asn/PKCS8PrivateKeyDecoder.java000066400000000000000000000037001422604312300273670ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.asn; import java.io.IOException; import org.bouncycastle.asn1.ASN1InputStream; import org.bouncycastle.asn1.pkcs.EncryptedPrivateKeyInfo; import org.bouncycastle.asn1.pkcs.PBEParameter; import org.bouncycastle.asn1.pkcs.PBES2Parameters; import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; import org.bouncycastle.asn1.x509.AlgorithmIdentifier; import org.bouncycastle.crypto.params.AsymmetricKeyParameter; import org.bouncycastle.crypto.util.PrivateKeyFactory; import org.cryptacular.EncodingException; import org.cryptacular.pbe.EncryptionScheme; import org.cryptacular.pbe.PBES1Algorithm; import org.cryptacular.pbe.PBES1EncryptionScheme; import org.cryptacular.pbe.PBES2EncryptionScheme; /** * Decodes PEM or DER-encoded PKCS#8 private keys. * * @author Middleware Services */ public class PKCS8PrivateKeyDecoder extends AbstractPrivateKeyDecoder { @Override protected byte[] decryptKey(final byte[] encrypted, final char[] password) { final EncryptionScheme scheme; final EncryptedPrivateKeyInfo ki = EncryptedPrivateKeyInfo.getInstance(tryConvertPem(encrypted)); final AlgorithmIdentifier alg = ki.getEncryptionAlgorithm(); if (PKCSObjectIdentifiers.id_PBES2.equals(alg.getAlgorithm())) { scheme = new PBES2EncryptionScheme(PBES2Parameters.getInstance(alg.getParameters()), password); } else { scheme = new PBES1EncryptionScheme( PBES1Algorithm.fromOid(alg.getAlgorithm().getId()), PBEParameter.getInstance(alg.getParameters()), password); } return scheme.decrypt(ki.getEncryptedData()); } @Override protected AsymmetricKeyParameter decodeASN1(final byte[] encoded) { try { return PrivateKeyFactory.createKey(new ASN1InputStream(encoded).readObject().getEncoded()); } catch (IOException e) { throw new EncodingException("ASN.1 decoding error", e); } } } cryptacular-1.2.5/src/main/java/org/cryptacular/asn/PublicKeyDecoder.java000066400000000000000000000017621422604312300264300ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.asn; import java.io.IOException; import org.bouncycastle.asn1.ASN1InputStream; import org.bouncycastle.crypto.params.AsymmetricKeyParameter; import org.bouncycastle.crypto.util.PublicKeyFactory; import org.cryptacular.EncodingException; import org.cryptacular.util.PemUtil; /** * Decodes public keys formatted in an X.509 SubjectPublicKeyInfo structure in either PEM or DER encoding. * * @author Middleware Services */ public class PublicKeyDecoder implements ASN1Decoder { @Override public AsymmetricKeyParameter decode(final byte[] encoded, final Object... args) { try { if (PemUtil.isPem(encoded)) { return PublicKeyFactory.createKey(PemUtil.decode(encoded)); } return PublicKeyFactory.createKey(new ASN1InputStream(encoded).readObject().getEncoded()); } catch (IOException e) { throw new EncodingException("ASN.1 decoding error", e); } } } cryptacular-1.2.5/src/main/java/org/cryptacular/bean/000077500000000000000000000000001422604312300225265ustar00rootroot00000000000000cryptacular-1.2.5/src/main/java/org/cryptacular/bean/AEADBlockCipherBean.java000066400000000000000000000061361422604312300267650ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.bean; import java.io.InputStream; import java.io.OutputStream; import java.security.KeyStore; import javax.crypto.SecretKey; import org.bouncycastle.crypto.modes.AEADBlockCipher; import org.bouncycastle.crypto.params.AEADParameters; import org.bouncycastle.crypto.params.KeyParameter; import org.cryptacular.CiphertextHeader; import org.cryptacular.adapter.AEADBlockCipherAdapter; import org.cryptacular.generator.Nonce; import org.cryptacular.spec.Spec; /** * Cipher bean that performs encryption with a block cipher in AEAD mode (e.g. GCM, CCM). * * @author Middleware Services */ public class AEADBlockCipherBean extends AbstractBlockCipherBean { /** Mac size in bits. */ public static final int MAC_SIZE_BITS = 128; /** AEAD block cipher specification (algorithm, mode, padding). */ private Spec blockCipherSpec; /** Creates a new instance. */ public AEADBlockCipherBean() {} /** * Creates a new instance by specifying all properties. * * @param blockCipherSpec Block cipher specification. * @param keyStore Key store containing encryption key. * @param keyAlias Name of encryption key entry in key store. * @param keyPassword Password used to decrypt key entry in keystore. * @param nonce Nonce/IV generator. */ public AEADBlockCipherBean( final Spec blockCipherSpec, final KeyStore keyStore, final String keyAlias, final String keyPassword, final Nonce nonce) { super(keyStore, keyAlias, keyPassword, nonce); setBlockCipherSpec(blockCipherSpec); } /** @return Block cipher specification. */ public Spec getBlockCipherSpec() { return blockCipherSpec; } /** * Sets the AEAD block cipher specification. * * @param blockCipherSpec Describes a block cipher in terms of algorithm, mode, and padding. */ public void setBlockCipherSpec(final Spec blockCipherSpec) { this.blockCipherSpec = blockCipherSpec; } @Override public void encrypt(final InputStream input, final OutputStream output) { if (blockCipherSpec.toString().endsWith("CCM")) { throw new UnsupportedOperationException("CCM mode ciphers do not support chunked encryption."); } super.encrypt(input, output); } @Override public void decrypt(final InputStream input, final OutputStream output) { if (blockCipherSpec.toString().endsWith("CCM")) { throw new UnsupportedOperationException("CCM mode ciphers do not support chunked decryption."); } super.decrypt(input, output); } @Override protected AEADBlockCipherAdapter newCipher(final CiphertextHeader header, final boolean mode) { final AEADBlockCipher cipher = blockCipherSpec.newInstance(); final SecretKey key = lookupKey(header.getKeyName()); final AEADParameters params = new AEADParameters( new KeyParameter(key.getEncoded()), MAC_SIZE_BITS, header.getNonce(), header.encode()); cipher.init(mode, params); return new AEADBlockCipherAdapter(cipher); } } cryptacular-1.2.5/src/main/java/org/cryptacular/bean/AbstractBlockCipherBean.java000066400000000000000000000065611422604312300300400ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.bean; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.security.KeyStore; import org.cryptacular.CiphertextHeader; import org.cryptacular.StreamException; import org.cryptacular.adapter.BlockCipherAdapter; import org.cryptacular.generator.Nonce; import org.cryptacular.util.StreamUtil; /** * Base class for all cipher beans that use block cipher. * * @author Middleware Services */ public abstract class AbstractBlockCipherBean extends AbstractCipherBean { /** Creates a new instance. */ public AbstractBlockCipherBean() {} /** * Creates a new instance by specifying all properties. * * @param keyStore Key store containing encryption key. * @param keyAlias Name of encryption key entry in key store. * @param keyPassword Password used to decrypt key entry in keystore. * @param nonce Nonce/IV generator. */ public AbstractBlockCipherBean( final KeyStore keyStore, final String keyAlias, final String keyPassword, final Nonce nonce) { super(keyStore, keyAlias, keyPassword, nonce); } @Override protected byte[] process(final CiphertextHeader header, final boolean mode, final byte[] input) { final BlockCipherAdapter cipher = newCipher(header, mode); int outOff; final int inOff; final int length; final byte[] output; if (mode) { final byte[] headerBytes = header.encode(); final int outSize = headerBytes.length + cipher.getOutputSize(input.length); output = new byte[outSize]; System.arraycopy(headerBytes, 0, output, 0, headerBytes.length); inOff = 0; outOff = headerBytes.length; length = input.length; } else { outOff = 0; inOff = header.getLength(); length = input.length - inOff; final int outSize = cipher.getOutputSize(length); output = new byte[outSize]; } outOff += cipher.processBytes(input, inOff, length, output, outOff); outOff += cipher.doFinal(output, outOff); if (outOff < output.length) { final byte[] copy = new byte[outOff]; System.arraycopy(output, 0, copy, 0, outOff); return copy; } return output; } @Override protected void process( final CiphertextHeader header, final boolean mode, final InputStream input, final OutputStream output) { final BlockCipherAdapter cipher = newCipher(header, mode); final int outSize = cipher.getOutputSize(StreamUtil.CHUNK_SIZE); final byte[] outBuf = new byte[Math.max(outSize, StreamUtil.CHUNK_SIZE)]; StreamUtil.pipeAll( input, output, (in, inOff, len, out) -> { final int n = cipher.processBytes(in, inOff, len, outBuf, 0); out.write(outBuf, 0, n); }); final int n = cipher.doFinal(outBuf, 0); try { output.write(outBuf, 0, n); } catch (IOException e) { throw new StreamException(e); } } /** * Creates a new cipher adapter instance suitable for the block cipher used by this class. * * @param header Ciphertext header. * @param mode True for encryption; false for decryption. * * @return Block cipher adapter that wraps an initialized block cipher that is ready for use in the given mode. */ protected abstract BlockCipherAdapter newCipher(CiphertextHeader header, boolean mode); } cryptacular-1.2.5/src/main/java/org/cryptacular/bean/AbstractCipherBean.java000066400000000000000000000136231422604312300270620ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.bean; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.security.Key; import java.security.KeyStore; import javax.crypto.SecretKey; import org.cryptacular.CiphertextHeader; import org.cryptacular.CiphertextHeaderV2; import org.cryptacular.CryptoException; import org.cryptacular.EncodingException; import org.cryptacular.StreamException; import org.cryptacular.generator.Nonce; import org.cryptacular.util.CipherUtil; /** * Base class for all cipher beans. The base class assumes all ciphertext output will contain a prepended {@link * CiphertextHeaderV2} containing metadata that facilitates decryption. * * @author Middleware Services */ public abstract class AbstractCipherBean implements CipherBean { /** Keystore containing symmetric key(s). */ private KeyStore keyStore; /** Keystore entry for alias of current key. */ private String keyAlias; /** Password on private key entry. */ private String keyPassword; /** Nonce generator. */ private Nonce nonce; /** Creates a new instance. */ public AbstractCipherBean() {} /** * Creates a new instance by specifying all properties. * * @param keyStore Key store containing encryption key. * @param keyAlias Name of encryption key entry in key store. * @param keyPassword Password used to decrypt key entry in keystore. * @param nonce Nonce/IV generator. */ public AbstractCipherBean(final KeyStore keyStore, final String keyAlias, final String keyPassword, final Nonce nonce) { setKeyStore(keyStore); setKeyAlias(keyAlias); setKeyPassword(keyPassword); setNonce(nonce); } /** @return Keystore that contains the {@link SecretKey}. */ public KeyStore getKeyStore() { return keyStore; } /** * Sets the keystore containing encryption/decryption key(s). The keystore must contain a {@link SecretKey} entry * whose alias is given by {@link #setKeyAlias(String)}, which will be used at the encryption key. It may contain * additional symmetric keys to support, for example, key rollover where some existing ciphertexts have headers * specifying a different key. In general all keys used for outstanding ciphertexts should be contained in the * keystore. * * @param keyStore Keystore containing encryption key(s). */ public void setKeyStore(final KeyStore keyStore) { this.keyStore = keyStore; } /** @return Alias that specifies the {@link KeyStore} entry containing the {@link SecretKey}. */ public String getKeyAlias() { return keyAlias; } /** * Sets the keystore entry alias used to locate the current encryption key. * * @param keyAlias Alias of {@link SecretKey} used for encryption. */ public void setKeyAlias(final String keyAlias) { this.keyAlias = keyAlias; } /** * Sets the password used to access the encryption key. * * @param keyPassword Encryption key password. */ public void setKeyPassword(final String keyPassword) { this.keyPassword = keyPassword; } /** @return Nonce/IV generation strategy. */ public Nonce getNonce() { return nonce; } /** * Sets the nonce/IV generation strategy. * * @param nonce Nonce generator. */ public void setNonce(final Nonce nonce) { this.nonce = nonce; } @Override public byte[] encrypt(final byte[] input) throws CryptoException { return process(header(), true, input); } @Override public void encrypt(final InputStream input, final OutputStream output) throws CryptoException, StreamException { final CiphertextHeaderV2 header = header(); try { output.write(header.encode()); } catch (IOException e) { throw new StreamException(e); } process(header, true, input, output); } @Override public byte[] decrypt(final byte[] input) throws CryptoException, EncodingException { return process(CipherUtil.decodeHeader(input, this::lookupKey), false, input); } @Override public void decrypt(final InputStream input, final OutputStream output) throws CryptoException, EncodingException, StreamException { process(CipherUtil.decodeHeader(input, this::lookupKey), false, input, output); } /** * Looks up secret key entry in the {@link #keyStore}. * * @param alias Name of secret key entry. * * @return Secret key. */ protected SecretKey lookupKey(final String alias) { final Key key; try { key = keyStore.getKey(alias, keyPassword.toCharArray()); } catch (Exception e) { throw new CryptoException("Error accessing keystore entry " + alias, e); } if (key instanceof SecretKey) { return (SecretKey) key; } throw new CryptoException(alias + " is not a secret key"); } /** * Processes the given data under the action of the cipher. * * @param header Ciphertext header. * @param mode True for encryption; false for decryption. * @param input Data to process by cipher. * * @return Ciphertext data under encryption, plaintext data under decryption. */ protected abstract byte[] process(CiphertextHeader header, boolean mode, byte[] input); /** * Processes the given data under the action of the cipher. * * @param header Ciphertext header. * @param mode True for encryption; false for decryption. * @param input Stream containing input data. * @param output Stream that receives output of cipher. */ protected abstract void process(CiphertextHeader header, boolean mode, InputStream input, OutputStream output); /** * @return New ciphertext header for a pending encryption or decryption operation performed by this instance. */ private CiphertextHeaderV2 header() { final CiphertextHeaderV2 header = new CiphertextHeaderV2(nonce.generate(), keyAlias); header.setKeyLookup(this::lookupKey); return header; } } cryptacular-1.2.5/src/main/java/org/cryptacular/bean/AbstractHashBean.java000066400000000000000000000052341422604312300265320ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.bean; import org.bouncycastle.crypto.Digest; import org.cryptacular.spec.Spec; import org.cryptacular.util.HashUtil; /** * Abstract base class for all hash beans. * * @author Middleware Services */ public abstract class AbstractHashBean { /** Digest specification. */ private Spec digestSpec; /** Number of hash rounds. */ private int iterations = 1; /** Creates a new instance. */ public AbstractHashBean() {} /** * Creates a new instance by specifying all properties. * * @param digestSpec Digest specification. * @param iterations Number of hash rounds. */ public AbstractHashBean(final Spec digestSpec, final int iterations) { setDigestSpec(digestSpec); setIterations(iterations); } /** @return Digest specification that determines the instance of {@link Digest} used to compute the hash. */ public Spec getDigestSpec() { return digestSpec; } /** * Sets the digest specification that determines the instance of {@link Digest} used to compute the hash. * * @param digestSpec Digest algorithm specification. */ public void setDigestSpec(final Spec digestSpec) { this.digestSpec = digestSpec; } /** @return Number of iterations the digest function is applied to the input data. */ public int getIterations() { return iterations; } /** * Sets the number of iterations the digest function is applied to the input data. * * @param iterations Number of hash rounds. Default value is 1. */ public void setIterations(final int iterations) { if (iterations < 1) { throw new IllegalArgumentException("Iterations must be positive"); } this.iterations = iterations; } /** * Hashes the given data. * * @param data Data to hash. * * @return Digest output. */ protected byte[] hashInternal(final Object... data) { return HashUtil.hash(digestSpec.newInstance(), iterations, data); } /** * Compares the hash of the given data against a known hash output. * * @param hash Known hash value. If the length of the array is greater than the length of the digest output, * anything beyond the digest length is considered salt data that is hashed after the * input data. * @param data Data to hash. * * @return True if hashed data equals known hash output, false otherwise. */ protected boolean compareInternal(final byte[] hash, final Object... data) { return HashUtil.compareHash(digestSpec.newInstance(), hash, iterations, data); } } cryptacular-1.2.5/src/main/java/org/cryptacular/bean/BCryptHashBean.java000066400000000000000000000244611422604312300261750ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.bean; import java.nio.ByteBuffer; import java.nio.CharBuffer; import java.nio.charset.StandardCharsets; import org.bouncycastle.crypto.generators.BCrypt; import org.cryptacular.CryptoException; import org.cryptacular.StreamException; import org.cryptacular.codec.Base64Decoder; import org.cryptacular.codec.Base64Encoder; import org.cryptacular.codec.Decoder; import org.cryptacular.codec.Encoder; import org.cryptacular.util.ByteUtil; /** * {@link HashBean} implementation that uses the bcrypt algorithm for hashing. Hash strings of the following * format are supported: *
* * $2n$cost$xxxxxxxxxxxxxxxxxxxxxxxxyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy * * where: * n is an optional bcrypt algorithm version (typically "a" or "b") * 4 ≤ cost ≤ 31 * x is 22 characters of encoded salt * y is 31 characters of encoded hash bytes * *

* The encoding for salt and hash bytes is a variant of base-64 encoding without padding in the following alphabet: *

*
* ./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 * * @author Middleware Services */ public class BCryptHashBean implements HashBean { /** Custom base-64 alphabet. */ private static final String ALPHABET = "./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; /** BCrypt cost factor in the range [4, 31]. Default value is {@value}. */ private int cost = 12; /** BCrypt version used when computing hashes. Default value is {@value}. */ private String version = "2b"; /** Creates a new instance. */ public BCryptHashBean() {} /** * Creates a new instance that uses the given cost factor when hashing. * * @param costFactor BCrypt cost in the range [4, 31]. */ public BCryptHashBean(final int costFactor) { setCost(costFactor); } /** * Sets the bcrypt cost factor. * * @param costFactor BCrypt cost in the range [4, 31]. */ public void setCost(final int costFactor) { if (costFactor < 4 || costFactor > 31) { throw new IllegalArgumentException("Cost must be in the range [4, 31]."); } cost = costFactor; } /** * Sets the bcrypt version. * * @param ver Bcrypt version, e.g. "2b" */ public void setVersion(final String ver) { if (!ver.startsWith("2") && ver.length() <= 2) { throw new IllegalArgumentException("Invalid version: " + ver); } version = ver; } /** * Compute a bcrypt hash of the form $2n$cost$xxxxxxxxxxxxxxxxxxxxxxxxyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy * given a salt and a password. * @param data A 2-element array containing salt and password. The salt may be encoded per the bcrypt standard * or raw bytes. * * @return An encoded bcrypt hash, yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy in the specification above. * * @throws CryptoException on bcrypt algorithm errors. */ @Override public String hash(final Object... data) throws CryptoException { if (data.length != 2) { throw new IllegalArgumentException("Expected exactly two elements in data array but got " + data.length); } return encode(BCrypt.generate(password(version, data[1]), salt(data[0]), cost), 23); } /** * Compares a bcrypt hash of the form $2n$cost$xxxxxxxxxxxxxxxxxxxxxxxxyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy * with the computed hash from the given password. The bcrypt algorithm parameters are derived from the reference * bcrypt hash string. * * @param data A 1-element array containing password. * * @return True if the computed hash is exactly equal to the reference hash, false otherwise. * * @throws CryptoException on bcrypt algorithm errors. */ @Override public boolean compare(final String hash, final Object... data) throws CryptoException, StreamException { if (data.length != 1) { throw new IllegalArgumentException("Expected exactly one element in data array but got " + data.length); } final BCryptParameters params = new BCryptParameters(hash); final byte[] computed = BCrypt.generate(password(params.getVersion(), data[0]), params.getSalt(), params.getCost()); for (int i = 0; i < 23; i++) { if (params.getHash()[i] != computed[i]) { return false; } } return true; } /** * Encodes an input byte array into a string using the configured encoder. * * @param bytes Input bytes to encode. * @param length Number of bytes of input to encode. * * @return Input encoded as a string. */ private static String encode(final byte[] bytes, final int length) { final Encoder encoder = new Base64Encoder.Builder().setAlphabet(ALPHABET).setPadding(false).build(); // Only want 184 bits (23 bytes) of the output final ByteBuffer input = ByteBuffer.wrap(bytes, 0, length); final CharBuffer output = CharBuffer.allocate(encoder.outputSize(length)); encoder.encode(input, output); encoder.finalize(output); return output.flip().toString(); } /** * Decodes an input string into a byte array using the configured decoder. * * @param input Input string to decode. * @param length Desired output size in bytes. * * @return Input decoded as a byte array. */ private static byte[] decode(final String input, final int length) { final Decoder decoder = new Base64Decoder.Builder().setAlphabet(ALPHABET).setPadding(false).build(); final ByteBuffer output = ByteBuffer.allocate(decoder.outputSize(input.length())); decoder.decode(CharBuffer.wrap(input), output); decoder.finalize(output); output.flip(); if (output.limit() != length) { throw new IllegalArgumentException("Input is not of the expected size: " + output.limit() + "!=" + length); } return ByteUtil.toArray(output); } /** * Converts an input object into a salt as an array of bytes. * * @param data Input salt as a byte array or encoded string. * * @return Salt as byte array. */ private static byte[] salt(final Object data) { if (data instanceof byte[]) { return (byte[]) data; } else if (data instanceof String) { return decode((String) data, 16); } throw new IllegalArgumentException("Expected byte array or base-64 string."); } /** * Converts an input object into a password as an array of UTF-8 bytes. A null terminator is added if the supplied * data does not end with one. * * @param version Bcrypt version, e.g. "2a". * @param data Input password. * * @return Null terminated password as UTF-8 byte array. */ private static byte[] password(final String version, final Object data) { if (data instanceof byte[]) { final byte[] origData = (byte[]) data; final byte[] newData; if (origData[origData.length - 1] != 0x00) { newData = new byte[origData.length + 1]; System.arraycopy(origData, 0, newData, 0, origData.length); newData[newData.length - 1] = 0x00; } else { newData = origData; } return newData; } final StringBuilder sb = new StringBuilder(); if (data instanceof char[]) { sb.append((char[]) data); } else if (data instanceof String) { sb.append((String) data); } else { throw new IllegalArgumentException("Expected byte array or string."); } if (sb.charAt(sb.length() - 1) != '\0') { // Version 2a and later requires null terminator on password sb.append('\0'); } return sb.toString().getBytes(StandardCharsets.UTF_8); } /** * Handles encoding and decoding a bcrypt hash of the form * $2n$cost$xxxxxxxxxxxxxxxxxxxxxxxxyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy. */ public static class BCryptParameters { /** bcrypt version. */ private final String version; /** bcrypt cost. */ private final int cost; /** bcrypt salt. */ private final byte[] salt; /** bcrypt hash. */ private final byte[] hash; /** * Decodes bcrypt parameters from a string. * * @param bCryptString bcrypt hash of the form * $2n$cost$xxxxxxxxxxxxxxxxxxxxxxxxyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy */ protected BCryptParameters(final String bCryptString) { if (!bCryptString.startsWith("$2")) { throw new IllegalArgumentException("Expected bcrypt hash of the form $2n$cost$salthash"); } final String[] parts = bCryptString.split("\\$"); if (parts.length != 4) { throw new IllegalArgumentException("Invalid bcrypt hash"); } version = parts[1]; cost = Integer.parseInt(parts[2]); salt = decode(parts[3].substring(0, 22), 16); hash = decode(parts[3].substring(22), 23); } /** @return bcrypt version. */ public String getVersion() { return version; } /** @return bcrypt cost in the range [4, 31]. */ public int getCost() { return cost; } /** @return bcrypt salt. */ public byte[] getSalt() { return salt; } /** @return bcrypt hash. */ public byte[] getHash() { return hash; } /** * Produces an encoded bcrypt hash string from bcrypt parameter data. * * @return Bcrypt hash of the form $2n$cost$xxxxxxxxxxxxxxxxxxxxxxxxyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy. */ public String encode() { return new StringBuilder(60) .append('$') .append(version) .append('$') .append(cost) .append('$') .append(BCryptHashBean.encode(salt, 16)) .append(BCryptHashBean.encode(hash, 23)) .toString(); } /** * Produces an encoded bcrypt hash string from bcrypt parameters and a provided hash string. * * @param hash Encoded bcrypt hash bytes; e.g. the value produced from {@link #hash(Object...)}. * * @return Bcrypt hash of the form $2n$cost$xxxxxxxxxxxxxxxxxxxxxxxxyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy. */ public String encode(final String hash) { return new StringBuilder(60) .append('$') .append(version) .append('$') .append(cost) .append('$') .append(BCryptHashBean.encode(salt, 16)) .append(hash) .toString(); } } } cryptacular-1.2.5/src/main/java/org/cryptacular/bean/BufferedBlockCipherBean.java000066400000000000000000000052241422604312300300120ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.bean; import java.security.KeyStore; import org.bouncycastle.crypto.BufferedBlockCipher; import org.bouncycastle.crypto.CipherParameters; import org.bouncycastle.crypto.params.KeyParameter; import org.bouncycastle.crypto.params.ParametersWithIV; import org.cryptacular.CiphertextHeader; import org.cryptacular.adapter.BufferedBlockCipherAdapter; import org.cryptacular.generator.Nonce; import org.cryptacular.spec.Spec; /** * Cipher bean that performs symmetric encryption/decryption using a standard block cipher in a standard mode (e.g. CBC, * OFB) with padding to support processing inputs of arbitrary length. * * @author Middleware Services */ public class BufferedBlockCipherBean extends AbstractBlockCipherBean { /** Block cipher specification (algorithm, mode, padding). */ private Spec blockCipherSpec; /** Creates a new instance. */ public BufferedBlockCipherBean() {} /** * Creates a new instance by specifying all properties. * * @param blockCipherSpec Block cipher specification. * @param keyStore Key store containing encryption key. * @param keyAlias Name of encryption key entry in key store. * @param keyPassword Password used to decrypt key entry in keystore. * @param nonce Nonce/IV generator. */ public BufferedBlockCipherBean( final Spec blockCipherSpec, final KeyStore keyStore, final String keyAlias, final String keyPassword, final Nonce nonce) { super(keyStore, keyAlias, keyPassword, nonce); setBlockCipherSpec(blockCipherSpec); } /** @return Block cipher specification. */ public Spec getBlockCipherSpec() { return blockCipherSpec; } /** * Sets the block cipher specification. * * @param blockCipherSpec Describes a block cipher in terms of algorithm, mode, and padding. */ public void setBlockCipherSpec(final Spec blockCipherSpec) { this.blockCipherSpec = blockCipherSpec; } @Override protected BufferedBlockCipherAdapter newCipher(final CiphertextHeader header, final boolean mode) { final BufferedBlockCipher cipher = blockCipherSpec.newInstance(); CipherParameters params = new KeyParameter(lookupKey(header.getKeyName()).getEncoded()); final String algName = cipher.getUnderlyingCipher().getAlgorithmName(); if (algName.endsWith("CBC") || algName.endsWith("OFB") || algName.endsWith("CFB")) { params = new ParametersWithIV(params, header.getNonce()); } cipher.init(mode, params); return new BufferedBlockCipherAdapter(cipher); } } cryptacular-1.2.5/src/main/java/org/cryptacular/bean/CipherBean.java000066400000000000000000000042311422604312300253710ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.bean; import java.io.InputStream; import java.io.OutputStream; import org.cryptacular.CryptoException; import org.cryptacular.StreamException; /** * Bean that performs encryption/decryption using a symmetric cipher. * * @author Middleware Services */ public interface CipherBean { /** * Encrypts the input data using a symmetric cipher. * * @param input Plaintext data to encrypt. * * @return Ciphertext output. * * @throws CryptoException on underlying cipher data handling errors. */ byte[] encrypt(byte[] input) throws CryptoException; /** * Encrypts the data from the input stream onto the output stream using a symmetric cipher. * *

The caller is responsible for providing and managing the streams (e.g. closing them when finished).

* * @param input Input stream containing plaintext data to encrypt. * @param output Output stream containing ciphertext produced by cipher in encryption mode. * * @throws CryptoException on underlying cipher data handling errors. * @throws StreamException on stream IO errors. */ void encrypt(InputStream input, OutputStream output) throws CryptoException, StreamException; /** * Decrypts the input data using a block cipher. * * @param input Ciphertext data to encrypt. * * @return Plaintext output. * * @throws CryptoException on underlying cipher data handling errors. */ byte[] decrypt(byte[] input) throws CryptoException; /** * Decrypts the data from the input stream onto the output stream using a symmetric cipher. * *

The caller is responsible for providing and managing the streams (e.g. closing them when finished).

* * @param input Input stream containing ciphertext data to decrypt. * @param output Output stream containing plaintext produced by cipher in decryption mode. * * @throws CryptoException on underlying cipher data handling errors. * @throws StreamException on stream IO errors. */ void decrypt(InputStream input, OutputStream output) throws CryptoException, StreamException; } cryptacular-1.2.5/src/main/java/org/cryptacular/bean/EncodingHashBean.java000066400000000000000000000120211422604312300265050ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.bean; import org.bouncycastle.crypto.Digest; import org.bouncycastle.util.Arrays; import org.cryptacular.CryptoException; import org.cryptacular.EncodingException; import org.cryptacular.StreamException; import org.cryptacular.codec.Codec; import org.cryptacular.spec.Spec; import org.cryptacular.util.CodecUtil; /** * Computes a hash in an encoded format, e.g. hex, base64. * * @author Middleware Services */ public class EncodingHashBean extends AbstractHashBean implements HashBean { /** Determines kind of encoding. */ private Spec codecSpec; /** Whether data provided to this bean includes a salt. */ private boolean salted; /** Creates a new instance. */ public EncodingHashBean() {} /** * Creates a new instance that will not be salted. Delegates to {@link #EncodingHashBean(Spec, Spec, int, boolean)}. * * @param codecSpec Digest specification. * @param digestSpec Digest specification. */ public EncodingHashBean(final Spec codecSpec, final Spec digestSpec) { this(codecSpec, digestSpec, 1, false); } /** * Creates a new instance that will not be salted. Delegates to {@link #EncodingHashBean(Spec, Spec, int, boolean)}. * * @param codecSpec Digest specification. * @param digestSpec Digest specification. * @param iterations Number of hash rounds. */ public EncodingHashBean(final Spec codecSpec, final Spec digestSpec, final int iterations) { this(codecSpec, digestSpec, iterations, false); } /** * Creates a new instance by specifying all properties. * * @param codecSpec Digest specification. * @param digestSpec Digest specification. * @param iterations Number of hash rounds. * @param salted Whether hash data will be salted. */ public EncodingHashBean( final Spec codecSpec, final Spec digestSpec, final int iterations, final boolean salted) { super(digestSpec, iterations); setCodecSpec(codecSpec); setSalted(salted); } /** @return Codec specification that determines the encoding applied to the hash output bytes. */ public Spec getCodecSpec() { return codecSpec; } /** * Sets the codec specification that determines the encoding applied to the hash output bytes. * * @param codecSpec Codec specification, e.g. {@link org.cryptacular.spec.CodecSpec#BASE64}, {@link * org.cryptacular.spec.CodecSpec#HEX}. */ public void setCodecSpec(final Spec codecSpec) { this.codecSpec = codecSpec; } /** * Whether data provided to {@link #hash(Object...)} includes a salt as the last parameter. * * @return whether hash data includes a salt */ public boolean isSalted() { return salted; } /** * Sets whether {@link #hash(Object...)} should expect a salt as the last parameter. * * @param salted whether hash data includes a salt */ public void setSalted(final boolean salted) { this.salted = salted; } /** * Hashes the given data. If {@link #isSalted()} is true then the last parameter MUST be a byte array containing the * salt. The salt value will be appended to the encoded hash that is returned. * * @param data Data to hash. * * @return Encoded digest output, including a salt if provided. * * @throws CryptoException on hash computation errors. * @throws EncodingException on encoding errors. * @throws StreamException on stream IO errors. */ @Override public String hash(final Object... data) throws CryptoException, EncodingException, StreamException { if (salted) { if (data.length < 2 || !(data[data.length - 1] instanceof byte[])) { throw new IllegalArgumentException("Last parameter must be a salt of type byte[]"); } final byte[] hashSalt = (byte[]) data[data.length - 1]; return CodecUtil.encode(codecSpec.newInstance().getEncoder(), Arrays.concatenate(hashInternal(data), hashSalt)); } return CodecUtil.encode(codecSpec.newInstance().getEncoder(), hashInternal(data)); } /** * Compares a known hash value with the hash of the given data. * * @param hash Known encoded hash value. If the length of the hash bytes after decoding is greater than the length * of the digest output, anything beyond the digest length is considered salt data that is hashed * after the input data. * @param data Data to hash. * * @return True if the hashed data matches the given hash, false otherwise. * * @throws CryptoException on hash computation errors. * @throws EncodingException on encoding errors. * @throws StreamException on stream IO errors. */ @Override public boolean compare(final String hash, final Object... data) throws CryptoException, EncodingException, StreamException { return compareInternal(CodecUtil.decode(codecSpec.newInstance().getDecoder(), hash), data); } } cryptacular-1.2.5/src/main/java/org/cryptacular/bean/FactoryBean.java000066400000000000000000000005211422604312300255640ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.bean; /** * Factory bean strategy interface. * * @param Type produced by factory. * * @author Middleware Services */ public interface FactoryBean { /** @return New instance of the type handled by this factory. */ T newInstance(); } cryptacular-1.2.5/src/main/java/org/cryptacular/bean/HashBean.java000066400000000000000000000031511422604312300250420ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.bean; import org.cryptacular.CryptoException; import org.cryptacular.StreamException; /** * Strategy interface to support beans that produce hash outputs in various formats, e.g. raw bytes, hex output, etc. * * @param Type of output (e.g. byte[], string) produced by hash bean. * * @author Middleware Services */ public interface HashBean { /** * Hashes the given data. * * @param data Data to hash. Callers should expect support for at least the following types: byte[], * {@link CharSequence}, {@link java.io.InputStream}, and {@link org.cryptacular.io.Resource}. Unless * otherwise noted, character data is processed in the UTF-8 character set; if another * character set is desired, the caller should convert to byte[] and provide the resulting * bytes. * * @return Digest output. * * @throws CryptoException on hash computation errors. * @throws StreamException on stream IO errors. */ T hash(Object... data) throws CryptoException, StreamException; /** * Compares a known hash value with the hash of the given data. * * @param hash Known hash value. * @param data Data to hash. * * @return True if the hashed data matches the given hash, false otherwise. * * @throws CryptoException on hash computation errors. * @throws StreamException on stream IO errors. */ boolean compare(T hash, Object... data) throws CryptoException, StreamException; } cryptacular-1.2.5/src/main/java/org/cryptacular/bean/KeyStoreBasedKeyFactoryBean.java000066400000000000000000000052341422604312300306700ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.bean; import java.security.Key; import java.security.KeyStore; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.security.UnrecoverableKeyException; import org.cryptacular.CryptoException; /** * Factory that produces either a {@link javax.crypto.SecretKey} or {@link java.security.PrivateKey}. * *

from a {@link KeyStore}.

* * @param Type of key, either {@link javax.crypto.SecretKey} or {@link java.security.PrivateKey}. * * @author Middleware Services */ public class KeyStoreBasedKeyFactoryBean implements FactoryBean { /** Keystore containing secret key. */ private KeyStore keyStore; /** Alias of keystore entry containing secret key. */ private String alias; /** Password required to read key entry. */ private String password; /** Creates a new instance. */ public KeyStoreBasedKeyFactoryBean() {} /** * Creates a new instance by specifying all properties. * * @param keyStore Key store containing encryption key. * @param alias Name of encryption key entry in key store. * @param password Password used to decrypt key entry in keystore. */ public KeyStoreBasedKeyFactoryBean(final KeyStore keyStore, final String alias, final String password) { setKeyStore(keyStore); setAlias(alias); setPassword(password); } /** @return Keystore that contains the {@link #keyStore}. */ public KeyStore getKeyStore() { return keyStore; } /** * Sets the keystore that contains the key. * * @param keyStore Non-null keystore. */ public void setKeyStore(final KeyStore keyStore) { this.keyStore = keyStore; } /** @return Alias that specifies the {@link KeyStore} entry containing the key. */ public String getAlias() { return alias; } /** * Sets the alias that specifies the {@link KeyStore} entry containing the key. * * @param alias Keystore alias of key entry. */ public void setAlias(final String alias) { this.alias = alias; } /** * Sets the password used to access the key entry. * * @param password Key entry password. */ public void setPassword(final String password) { this.password = password; } @Override @SuppressWarnings("unchecked") public T newInstance() { final Key key; try { key = keyStore.getKey(alias, password.toCharArray()); } catch (KeyStoreException | NoSuchAlgorithmException | UnrecoverableKeyException e) { throw new CryptoException("Error accessing keystore entry " + alias, e); } return (T) key; } } cryptacular-1.2.5/src/main/java/org/cryptacular/bean/KeyStoreFactoryBean.java000066400000000000000000000060441422604312300272600ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.bean; import java.io.IOException; import java.security.KeyStore; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.security.cert.CertificateException; import org.cryptacular.CryptoException; import org.cryptacular.StreamException; import org.cryptacular.io.Resource; /** * Factory bean that produces a {@link KeyStore} from a file or URI. * * @author Middleware Services */ public class KeyStoreFactoryBean implements FactoryBean { /** Default keystore type, {@value}. */ public static final String DEFAULT_TYPE = "JCEKS"; /** Keystore type, e.g. JKS, JCEKS, BKS. */ private String type = DEFAULT_TYPE; /** Resource that provides encoded keystore data. */ private Resource resource; /** Keystore password. */ private String password; /** Creates a new instance. */ public KeyStoreFactoryBean() {} /** * Creates a new instance by specifying all properties. * * @param resource Resource containing encoded keystore data. * @param type Keystore type, e.g. JCEKS. * @param password Password used to decrypt key entry in keystore. */ public KeyStoreFactoryBean(final Resource resource, final String type, final String password) { setResource(resource); setType(type); setPassword(password); } /** @return Keystore type. */ public String getType() { return type; } /** * Sets the keystore type. * * @param type JCEKS (default), JKS, PKCS12, or BKS. NOTE: BKS type is supported only when BC * provider is installed. */ public void setType(final String type) { this.type = type; } /** @return Resource that provides encoded keystore data. */ public Resource getResource() { return resource; } /** * Sets the resource that provides encoded keystore data. * * @param resource Keystore resource. */ public void setResource(final Resource resource) { this.resource = resource; } /** * Sets the keystore password required to decrypt an encrypted keystore. * * @param password Keystore password. */ public void setPassword(final String password) { this.password = password; } @Override public KeyStore newInstance() { if (resource == null) { throw new IllegalStateException("Must provide resource."); } final KeyStore store; try { store = KeyStore.getInstance(type); } catch (KeyStoreException e) { String message = "Unsupported keystore type " + type; if ("BKS".equalsIgnoreCase(type)) { message += ". Is BC provider installed?"; } throw new CryptoException(message, e); } try { store.load(resource.getInputStream(), password.toCharArray()); } catch (CertificateException | NoSuchAlgorithmException e) { throw new CryptoException("Error loading keystore", e); } catch (IOException e) { throw new StreamException(e); } return store; } } cryptacular-1.2.5/src/main/java/org/cryptacular/bean/PemBasedPrivateKeyFactoryBean.java000066400000000000000000000034241422604312300311760ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.bean; import java.security.PrivateKey; import org.cryptacular.EncodingException; import org.cryptacular.util.ByteUtil; import org.cryptacular.util.KeyPairUtil; import org.cryptacular.util.PemUtil; /** * Factory for creating a public key from a PEM-encoded private key in any format supported by {@link * KeyPairUtil#decodePrivateKey(byte[])}. Note that this component does not support encrypted private keys; see {@link * ResourceBasedPrivateKeyFactoryBean} for encryption support. * * @author Middleware Services * @see org.cryptacular.util.KeyPairUtil#decodePrivateKey(byte[]) * @see ResourceBasedPrivateKeyFactoryBean */ public class PemBasedPrivateKeyFactoryBean implements FactoryBean { /** PEM-encoded public key data. */ private String encodedKey; /** Creates a new instance. */ public PemBasedPrivateKeyFactoryBean() {} /** * Creates a new instance by specifying all properties. * * @param pemEncodedKey PEM-encoded private key data. */ public PemBasedPrivateKeyFactoryBean(final String pemEncodedKey) { setEncodedKey(pemEncodedKey); } /** @return PEM-encoded private key data. */ public String getEncodedKey() { return encodedKey; } /** * Sets the PEM-encoded private key data. * * @param pemEncodedKey PEM-encoded private key data. */ public void setEncodedKey(final String pemEncodedKey) { if (!PemUtil.isPem(ByteUtil.toBytes(pemEncodedKey))) { throw new IllegalArgumentException("Data is not PEM encoded."); } this.encodedKey = pemEncodedKey; } @Override public PrivateKey newInstance() throws EncodingException { return KeyPairUtil.decodePrivateKey(PemUtil.decode(encodedKey)); } } cryptacular-1.2.5/src/main/java/org/cryptacular/bean/PemBasedPublicKeyFactoryBean.java000066400000000000000000000042251422604312300310020ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.bean; import java.security.PublicKey; import org.cryptacular.EncodingException; import org.cryptacular.util.ByteUtil; import org.cryptacular.util.KeyPairUtil; import org.cryptacular.util.PemUtil; /** * Factory for creating a public key from a PEM-encoded string: * *
-----BEGIN PUBLIC KEY-----
 MIIBtzCCASsGByqGSM44BAEwggEeAoGBAOulifG+AGGBVGWEjunG4661rydB7eFy
 RfHzbwVAVaPU0H3zFcOY35z1l6Pk4ZANVHq7hCbViJBR7XyrkYKaUcaB0nSPLgg3
 vWWOmvGqhuR6tWRGbz4fyHl1urCRk9mrJum4mAJd3OlLugCyuIqozsYUtvJ5mlGe
 vir1zmxinKd7AhUA7fBEySYP53g7FLOlcEyuhIjvQAECgYBJ9baoGzn0zKpeteC4
 jfbGVuKrFksr2eeY0AFJOeTtyFkCnVqrNnF674eN1RAOwA2tzzhWZ96G0AGux8ah
 mGsNRbj/qaUTDNRWr7BPBIvDd+8LpMin4Cb5j4c/A7uOY+5WxhUm3TNifueBRohw
 h1NnexYQqpclcuTRA/ougLX48gOBhQACgYEA6Tw2khtb1g0vcHu6JRgggWPZVTuj
 /HOH3FyjufsfHogWKrlKebZ6hnQ73qAcEgLLYKctPdCX6wnpXN+BsQGYdTkc0FsU
 NZD4VW5L5kaWRiLVfE8x55wXdMZtXKWqg1vL6aXYZw7RFe9U9Ck+/AG90knThDC+
 xrX2FTDm6uC25rk=
 -----END PUBLIC KEY-----
* * @author Middleware Services * @see KeyPairUtil#decodePublicKey(byte[]) */ public class PemBasedPublicKeyFactoryBean implements FactoryBean { /** PEM-encoded public key data. */ private String encodedKey; /** Creates a new instance. */ public PemBasedPublicKeyFactoryBean() {} /** * Creates a new instance by specifying all properties. * * @param pemEncodedKey PEM-encoded public key data. */ public PemBasedPublicKeyFactoryBean(final String pemEncodedKey) { setEncodedKey(pemEncodedKey); } /** @return PEM-encoded public key data. */ public String getEncodedKey() { return encodedKey; } /** * Sets the PEM-encoded public key data. * * @param pemEncodedKey PEM-encoded public key data. */ public void setEncodedKey(final String pemEncodedKey) { if (!PemUtil.isPem(ByteUtil.toBytes(pemEncodedKey))) { throw new IllegalArgumentException("Data is not PEM encoded."); } this.encodedKey = pemEncodedKey; } @Override public PublicKey newInstance() throws EncodingException { return KeyPairUtil.decodePublicKey(PemUtil.decode(encodedKey)); } } cryptacular-1.2.5/src/main/java/org/cryptacular/bean/ResourceBasedPrivateKeyFactoryBean.java000066400000000000000000000050331422604312300322420ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.bean; import java.io.IOException; import java.security.PrivateKey; import org.cryptacular.EncodingException; import org.cryptacular.StreamException; import org.cryptacular.io.Resource; import org.cryptacular.util.KeyPairUtil; /** * Factory for reading a private from a {@link Resource} containing data in any of the formats supported by {@link * KeyPairUtil#readPrivateKey(java.io.InputStream, char[])}. * * @author Middleware Services * @see KeyPairUtil#readPrivateKey(java.io.InputStream, char[]) * @see KeyPairUtil#readPrivateKey(java.io.InputStream) */ public class ResourceBasedPrivateKeyFactoryBean implements FactoryBean { /** Resource containing key data. */ private Resource resource; /** Password required to decrypt an encrypted private key. */ private String password; /** Creates a new instance. */ public ResourceBasedPrivateKeyFactoryBean() {} /** * Creates a new instance capable of reading an unencrypted private key. * * @param resource Resource containing encoded key data. */ public ResourceBasedPrivateKeyFactoryBean(final Resource resource) { setResource(resource); } /** * Creates a new instance of reading an encrypted private key. * * @param resource Resource containing encoded key data. * @param decryptionPassword Password-based encryption key. */ public ResourceBasedPrivateKeyFactoryBean(final Resource resource, final String decryptionPassword) { setResource(resource); setPassword(decryptionPassword); } /** @return Resource containing key data. */ public Resource getResource() { return resource; } /** * Sets the resource containing key data. * * @param resource Resource containing key bytes. */ public void setResource(final Resource resource) { this.resource = resource; } /** * Sets the password-based key used to decrypt an encrypted private key. * * @param decryptionPassword Password-based encryption key. */ public void setPassword(final String decryptionPassword) { this.password = decryptionPassword; } @Override public PrivateKey newInstance() throws EncodingException, StreamException { try { if (password != null) { return KeyPairUtil.readPrivateKey(resource.getInputStream(), password.toCharArray()); } return KeyPairUtil.readPrivateKey(resource.getInputStream()); } catch (IOException e) { throw new StreamException(e); } } } cryptacular-1.2.5/src/main/java/org/cryptacular/bean/ResourceBasedPublicKeyFactoryBean.java000066400000000000000000000031241422604312300320450ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.bean; import java.io.IOException; import java.security.PublicKey; import org.cryptacular.EncodingException; import org.cryptacular.StreamException; import org.cryptacular.io.Resource; import org.cryptacular.util.KeyPairUtil; /** * Factory for creating a public key from a {@link Resource} containing data in any of the formats supported by {@link * KeyPairUtil#readPublicKey(java.io.InputStream)}. * * @author Middleware Services * @see KeyPairUtil#readPublicKey(java.io.InputStream) */ public class ResourceBasedPublicKeyFactoryBean implements FactoryBean { /** Resource containing key data. */ private Resource resource; /** Creates a new instance. */ public ResourceBasedPublicKeyFactoryBean() {} /** * Creates a new instance by specifying all properties. * * @param resource Resource containing encoded key data. */ public ResourceBasedPublicKeyFactoryBean(final Resource resource) { setResource(resource); } /** @return Resource containing key data. */ public Resource getResource() { return resource; } /** * Sets the resource containing key data. * * @param resource Resource containing key bytes. */ public void setResource(final Resource resource) { this.resource = resource; } @Override public PublicKey newInstance() throws EncodingException, StreamException { try { return KeyPairUtil.readPublicKey(resource.getInputStream()); } catch (IOException e) { throw new StreamException(e); } } } cryptacular-1.2.5/src/main/java/org/cryptacular/bean/ResourceBasedSecretKeyFactoryBean.java000066400000000000000000000036411422604312300320600ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.bean; import java.io.IOException; import javax.crypto.SecretKey; import javax.crypto.spec.SecretKeySpec; import org.cryptacular.StreamException; import org.cryptacular.io.Resource; import org.cryptacular.util.StreamUtil; /** * Factory that produces a {@link SecretKey} from a {@link Resource}. * * @author Middleware Services */ public class ResourceBasedSecretKeyFactoryBean implements FactoryBean { /** Key algorithm. */ private String algorithm; /** Resource containing key data. */ private Resource resource; /** Creates a new instance. */ public ResourceBasedSecretKeyFactoryBean() {} /** * Creates a new instance by specifying all properties. * * @param resource Resource containing encoded key data. * @param algorithm Algorithm name of cipher with which key will be used. */ public ResourceBasedSecretKeyFactoryBean(final Resource resource, final String algorithm) { setResource(resource); setAlgorithm(algorithm); } /** @return Key algorithm name, e.g. AES. */ public String getAlgorithm() { return algorithm; } /** * Sets the key algorithm. * * @param algorithm Secret key algorithm, e.g. AES. */ public void setAlgorithm(final String algorithm) { this.algorithm = algorithm; } /** @return Resource containing key data. */ public Resource getResource() { return resource; } /** * Sets the resource containing key data. * * @param resource Resource containing key bytes. */ public void setResource(final Resource resource) { this.resource = resource; } @Override public SecretKey newInstance() throws StreamException { try { return new SecretKeySpec(StreamUtil.readAll(resource.getInputStream()), algorithm); } catch (IOException e) { throw new StreamException(e); } } } cryptacular-1.2.5/src/main/java/org/cryptacular/bean/SimpleHashBean.java000066400000000000000000000033001422604312300262100ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.bean; import org.bouncycastle.crypto.Digest; import org.cryptacular.CryptoException; import org.cryptacular.StreamException; import org.cryptacular.spec.Spec; /** * Computes a hash using an instance of {@link Digest} specified by {@link #setDigestSpec(org.cryptacular.spec.Spec)}. * * @author Middleware Services */ public class SimpleHashBean extends AbstractHashBean implements HashBean { /** Creates a new instance. */ public SimpleHashBean() {} /** * Creates a new instance by specifying all properties. * * @param digestSpec Digest specification. * @param iterations Number of hash rounds. */ public SimpleHashBean(final Spec digestSpec, final int iterations) { super(digestSpec, iterations); } @Override public byte[] hash(final Object... data) throws CryptoException, StreamException { return hashInternal(data); } /** * Compares a known hash value with the hash of the given data. * * @param hash Known hash value. If the length of the array is greater than the length of the digest output, * anything beyond the digest length is considered salt data that is hashed after the * input data. * @param data Data to hash. * * @return True if the hashed data matches the given hash, false otherwise. * * @throws CryptoException on hash computation errors. * @throws StreamException on stream IO errors. */ @Override public boolean compare(final byte[] hash, final Object... data) throws CryptoException, StreamException { return compareInternal(hash, data); } } cryptacular-1.2.5/src/main/java/org/cryptacular/codec/000077500000000000000000000000001422604312300226765ustar00rootroot00000000000000cryptacular-1.2.5/src/main/java/org/cryptacular/codec/AbstractBaseNDecoder.java000066400000000000000000000074671422604312300275210ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.codec; import java.nio.ByteBuffer; import java.nio.CharBuffer; import org.cryptacular.EncodingException; /** * Base decoder class for encoding schemes described in RFC 3548. * * @author Middleware Services */ public abstract class AbstractBaseNDecoder implements Decoder { /** Block of encoded characters. */ private final char[] block = new char[getBlockLength() / getBitsPerChar()]; /** Decoding table. */ private final byte[] table; /** Current position in character block. */ private int blockPos; /** Flag indicating whether input is padded. True by default. */ private boolean paddedInput = true; /** * Creates a new instance with given parameters. * * @param decodingTable Byte array indexed by characters in the character set encoding. */ public AbstractBaseNDecoder(final byte[] decodingTable) { table = decodingTable; } /** @return True if padded input is accepted (default), false otherwise. */ public boolean isPaddedInput() { return paddedInput; } /** * Determines whether padded input is accepted. * * @param enabled True to enable support for padded input, false otherwise. */ public void setPaddedInput(final boolean enabled) { this.paddedInput = enabled; } @Override public void decode(final CharBuffer input, final ByteBuffer output) throws EncodingException { char current; while (input.hasRemaining()) { current = input.get(); if (Character.isWhitespace(current) || current == '=') { continue; } block[blockPos++] = current; if (blockPos == block.length) { writeOutput(output, block.length); } } } @Override public void finalize(final ByteBuffer output) throws EncodingException { if (blockPos > 0) { writeOutput(output, blockPos); } } @Override public int outputSize(final int inputSize) { final int size; if (paddedInput) { size = inputSize; } else { // For unpadded input, add the maximum number of padding characters to get worst-case estimate size = inputSize + getBlockLength() / 8 - 1; } return size * getBitsPerChar() / 8; } /** @return Number of bits in a block of encoded characters. */ protected abstract int getBlockLength(); /** @return Number of bits encoding a single character. */ protected abstract int getBitsPerChar(); /** * Converts the given alphabet into a base-N decoding table. * * @param alphabet Decoding alphabet to use. * @param n Encoding base. * * @return Decoding table of 128 elements. */ protected static byte[] decodingTable(final String alphabet, final int n) { if (alphabet.length() != n) { throw new IllegalArgumentException("Alphabet must be exactly " + n + " characters long"); } final byte[] decodingTable = new byte[128]; for (int i = 0; i < n; i++) { decodingTable[(int) alphabet.charAt(i)] = (byte) i; } return decodingTable; } /** * Writes bytes in the current encoding block to the output buffer. * * @param output Output buffer. * @param len Number of characters to decode in current block. */ private void writeOutput(final ByteBuffer output, final int len) { long b; long value = 0; int shift = getBlockLength(); for (int i = 0; i < len; i++) { b = table[block[i] & 0x7F]; if (b < 0) { throw new EncodingException("Invalid character " + block[i]); } shift -= getBitsPerChar(); value |= b << shift; } final int stop = shift + getBitsPerChar() - 1; int offset = getBlockLength(); while (offset > stop) { offset -= 8; output.put((byte) ((value & (0xffL << offset)) >> offset)); } blockPos = 0; } } cryptacular-1.2.5/src/main/java/org/cryptacular/codec/AbstractBaseNEncoder.java000066400000000000000000000111761422604312300275230ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.codec; import java.nio.ByteBuffer; import java.nio.CharBuffer; import org.cryptacular.EncodingException; /** * Base encoder class for encoding schemes described in RFC 3548. * * @author Middleware Services */ public abstract class AbstractBaseNEncoder implements Encoder { /** Platform-specific line terminator string, e.g. LF (Unix), CRLF (Windows). */ private static final String NEWLINE = System.lineSeparator(); /** Number of base64 characters per line. */ protected final int lineLength; /** Encoding character set. */ private final char[] charset; /** Number of bits in a block. */ private final int blockLength = getBlockLength(); /** Number of bits encoding a single character. */ private final int bitsPerChar = getBitsPerChar(); /** Initial bit mask for selecting characters in a block. */ private final long initialBitMask; /** Holds a block of bytes to encode. */ private long block; /** Number of bits in encode block remaining. */ private int remaining = blockLength; /** Number of characters written. */ private int outCount; /** Flag indicating whether output is padded. True by default. */ private boolean paddedOutput = true; /** * Creates a new instance with given parameters. * * @param characterSet Encoding character set. * @param charactersPerLine Number of characters per line. */ public AbstractBaseNEncoder(final char[] characterSet, final int charactersPerLine) { charset = characterSet; long mask = 0; for (int i = 1; i <= bitsPerChar; i++) { mask |= 1L << (blockLength - i); } initialBitMask = mask; lineLength = charactersPerLine; } /** * @return True if padded output is enabled (default), false otherwise. */ public boolean isPaddedOutput() { return paddedOutput; } /** * Sets the output padding mode. * * @param enabled True to enable padded output, false otherwise. */ public void setPaddedOutput(final boolean enabled) { this.paddedOutput = enabled; } @Override public void encode(final ByteBuffer input, final CharBuffer output) throws EncodingException { while (input.hasRemaining()) { remaining -= 8; block |= (input.get() & 0xffL) << remaining; if (remaining == 0) { writeOutput(output, 0); } } } @Override public void finalize(final CharBuffer output) throws EncodingException { if (remaining < blockLength) { // Floor division final int stop = remaining / bitsPerChar * bitsPerChar; writeOutput(output, stop); if (paddedOutput) { for (int i = stop; i > 0; i -= bitsPerChar) { output.put('='); } } } // Append trailing newline to make consistent with OpenSSL base64 output if (lineLength > 0 && output.position() > 0) { output.append(NEWLINE); } outCount = 0; } @Override public int outputSize(final int inputSize) { int len = (inputSize + (blockLength / 8) - 1) * 8 / bitsPerChar; if (lineLength > 0) { len += (len / lineLength + 1) * NEWLINE.length(); } return len; } /** @return Number of bits in a block of encoded characters. */ protected abstract int getBlockLength(); /** @return Number of bits encoding a single character. */ protected abstract int getBitsPerChar(); /** * Converts the given alphabet into a base-N encoding table. * * @param alphabet Encoding alphabet to use. * @param n Encoding base. * * @return Encoding table of N elements. */ protected static char[] encodingTable(final String alphabet, final int n) { if (alphabet.length() != n) { throw new IllegalArgumentException("Alphabet must be exactly " + n + " characters long"); } final char[] encodingTable = new char[n]; for (int i = 0; i < n; i++) { encodingTable[i] = alphabet.charAt(i); } return encodingTable; } /** * Writes bytes in the current encoding block to the output buffer. * * @param output Output buffer. * @param stop Bit shift stop position where data in current encoding block ends. */ private void writeOutput(final CharBuffer output, final int stop) { int shift = blockLength; long mask = initialBitMask; int index; while (shift > stop) { shift -= bitsPerChar; index = (int) ((block & mask) >> shift); output.put(charset[index]); outCount++; if (lineLength > 0 && outCount % lineLength == 0) { output.put(NEWLINE); } mask >>= bitsPerChar; } block = 0; remaining = blockLength; } } cryptacular-1.2.5/src/main/java/org/cryptacular/codec/Base32Codec.java000066400000000000000000000041331422604312300255170ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.codec; /** * Base 32 encoder/decoder pair. * * @author Middleware Services */ public class Base32Codec implements Codec { /** Encoder. */ private final Encoder encoder; /** Decoder. */ private final Decoder decoder; /** Custom alphabet to use. */ private final String customAlphabet; /** Whether input/output padding is supported. */ private final boolean padding; /** * Creates a new instance using the RFC 4328 alphabet, ABCDEFGHIJKLMNOPQRSTUVWXYZ234567. */ public Base32Codec() { encoder = new Base32Encoder(); decoder = new Base32Decoder(); customAlphabet = null; padding = true; } /** * Creates a new instance using the given 32-character alphabet. * * @param alphabet 32-character alphabet to use. */ public Base32Codec(final String alphabet) { this(alphabet, true); } /** * Creates a new instance using the given 32-character alphabet with option to enable/disable padding. * * @param alphabet 32-character alphabet to use. * @param inputOutputPadding True to enable support for padding, false otherwise. */ public Base32Codec(final String alphabet, final boolean inputOutputPadding) { customAlphabet = alphabet; padding = inputOutputPadding; encoder = newEncoder(); decoder = newDecoder(); } @Override public Encoder getEncoder() { return encoder; } @Override public Decoder getDecoder() { return decoder; } @Override public Encoder newEncoder() { final Base32Encoder encoder; if (customAlphabet != null) { encoder = new Base32Encoder(customAlphabet); } else { encoder = new Base32Encoder(); } encoder.setPaddedOutput(padding); return encoder; } @Override public Decoder newDecoder() { final Base32Decoder decoder; if (customAlphabet != null) { decoder = new Base32Decoder(customAlphabet); } else { decoder = new Base32Decoder(); } decoder.setPaddedInput(padding); return decoder; } } cryptacular-1.2.5/src/main/java/org/cryptacular/codec/Base32Decoder.java000066400000000000000000000020461422604312300260500ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.codec; /** * Stateful base 32 decoder with support for line breaks. * * @author Middleware Services */ public class Base32Decoder extends AbstractBaseNDecoder { /** Base-32 character decoding table. */ private static final byte[] DECODING_TABLE; /* Initializes the character decoding table. */ static { DECODING_TABLE = decodingTable("ABCDEFGHIJKLMNOPQRSTUVWXYZ234567", 32); } /** * Creates a new instance using the RFC 4648 alphabet, ABCDEFGHIJKLMNOPQRSTUVWXYZ234567, for decoding. */ public Base32Decoder() { super(DECODING_TABLE); } /** * Creates a new instance using the given 32-character alphabet for decoding. * * @param alphabet 32-character alphabet to use. */ public Base32Decoder(final String alphabet) { super(decodingTable(alphabet, 32)); } @Override protected int getBlockLength() { return 40; } @Override protected int getBitsPerChar() { return 5; } } cryptacular-1.2.5/src/main/java/org/cryptacular/codec/Base32Encoder.java000066400000000000000000000041301422604312300260560ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.codec; /** * Stateful base 32 encoder with support for configurable line breaks. * * @author Middleware Services */ public class Base32Encoder extends AbstractBaseNEncoder { /** Base 32 character encoding table. */ private static final char[] ENCODING_TABLE; /* Initializes the default character encoding table. */ static { ENCODING_TABLE = encodingTable("ABCDEFGHIJKLMNOPQRSTUVWXYZ234567", 32); } /** * Creates a new instance that produces base 32-encoded output in the RFC 4648 alphabet, * ABCDEFGHIJKLMNOPQRSTUVWXYZ234567, with no line breaks in the output. */ public Base32Encoder() { // Default to no line breaks. this(-1); } /** * Creates a new instance that produces base 32-encoded output in the RFC 4648 alphabet, * ABCDEFGHIJKLMNOPQRSTUVWXYZ234567, with the given number of characters per line in the output. * * @param charactersPerLine Number of characters per line. A zero or negative value disables line breaks. */ public Base32Encoder(final int charactersPerLine) { super(ENCODING_TABLE, charactersPerLine); } /** * Creates a new instance that produces base 32-encoded output in the given 32-character alphabet with no line * breaks in the output. * * @param alphabet 32-character alphabet to use. */ public Base32Encoder(final String alphabet) { this(alphabet, -1); } /** * Creates a new instance that produces base 32-encoded output in the given 32-character alphabet * with the given number of characters per line in the output. * * @param alphabet 32-character alphabet to use. * @param charactersPerLine Number of characters per line. A zero or negative value disables line breaks. */ public Base32Encoder(final String alphabet, final int charactersPerLine) { super(encodingTable(alphabet, 32), charactersPerLine); } @Override protected int getBlockLength() { return 40; } @Override protected int getBitsPerChar() { return 5; } } cryptacular-1.2.5/src/main/java/org/cryptacular/codec/Base64Codec.java000066400000000000000000000040771422604312300255330ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.codec; /** * Base 64 encoder/decoder pair. * * @author Middleware Services */ public class Base64Codec implements Codec { /** Encoder. */ private final Encoder encoder; /** Decoder. */ private final Decoder decoder; /** Custom alphabet to use. */ private final String customAlphabet; /** Whether input/output padding is supported. */ private final boolean padding; /** * Creates a new instance using the base-64 alphabet defined in RFC 4648. */ public Base64Codec() { encoder = new Base64Encoder(); decoder = new Base64Decoder(); customAlphabet = null; padding = true; } /** * Creates a new instance using the given 64-character alphabet. * * @param alphabet 64-character alphabet to use. */ public Base64Codec(final String alphabet) { this(alphabet, true); } /** * Creates a new instance using the given 64-character alphabet with option to enable/disable padding. * * @param alphabet 64-character alphabet to use. * @param inputOutputPadding True to enable support for padding, false otherwise. */ public Base64Codec(final String alphabet, final boolean inputOutputPadding) { customAlphabet = alphabet; padding = inputOutputPadding; encoder = newEncoder(); decoder = newDecoder(); } @Override public Encoder getEncoder() { return encoder; } @Override public Decoder getDecoder() { return decoder; } @Override public Encoder newEncoder() { final Base64Encoder encoder; if (customAlphabet != null) { encoder = new Base64Encoder(customAlphabet); } else { encoder = new Base64Encoder(); } encoder.setPaddedOutput(padding); return encoder; } @Override public Decoder newDecoder() { final Base64Decoder decoder; if (customAlphabet != null) { decoder = new Base64Decoder(customAlphabet); } else { decoder = new Base64Decoder(); } decoder.setPaddedInput(padding); return decoder; } } cryptacular-1.2.5/src/main/java/org/cryptacular/codec/Base64Decoder.java000066400000000000000000000061241422604312300260560ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.codec; /** * Stateful base 64 decoder with support for line breaks. * * @author Middleware Services */ public class Base64Decoder extends AbstractBaseNDecoder { /** Default base-64 character decoding table. */ private static final byte[] DEFAULT_DECODING_TABLE; /** URL and filesystem-safe base-64 character decoding table. */ private static final byte[] URLSAFE_DECODING_TABLE; /* Initializes the character decoding table. */ static { DEFAULT_DECODING_TABLE = decodingTable("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/", 64); URLSAFE_DECODING_TABLE = decodingTable("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_", 64); } /** Creates a new instance that decodes base 64-encoded input in the default character set. */ public Base64Decoder() { this(false); } /** * Creates a new instance that decodes base 64-encoded input in the optional URL-safe character set. * * @param urlSafe True to use URL and filesystem-safe character set, false otherwise. */ public Base64Decoder(final boolean urlSafe) { super(urlSafe ? URLSAFE_DECODING_TABLE : DEFAULT_DECODING_TABLE); } /** * Creates a new instance that decodes base-64 character data encoded in the given alphabet. * * @param alphabet Base-64 alphabet to use for decoding */ public Base64Decoder(final String alphabet) { super(decodingTable(alphabet, 64)); } @Override protected int getBlockLength() { return 24; } @Override protected int getBitsPerChar() { return 6; } /** * Builder for base-64 decoders. */ public static class Builder { /** URL-safe alphabet flag. */ private boolean urlSafe; /** Arbitrary alphbet. */ private String alphabet; /** Padding flag. */ private boolean padding; /** * Sets the URL-safe alphabet flag. * * @param safe True for URL-safe alphabet, false otherwise. * * @return This instance. */ public Builder setUrlSafe(final boolean safe) { urlSafe = safe; return this; } /** * Sets an arbitrary 64-character alphabet for decoding. * * @param alpha Alternative alphabet. * * @return This instance. */ public Builder setAlphabet(final String alpha) { alphabet = alpha; return this; } /** * Sets padding flag on the decoder. * * @param pad True for base-64 padding, false otherwise. * * @return This instance. */ public Builder setPadding(final boolean pad) { padding = pad; return this; } /** * Builds a base-64 decoder with the given options. * * @return New base-64 decoder instance. */ public Base64Decoder build() { final Base64Decoder decoder; if (alphabet != null) { decoder = new Base64Decoder(alphabet); } else { decoder = new Base64Decoder(urlSafe); } decoder.setPaddedInput(padding); return decoder; } } } cryptacular-1.2.5/src/main/java/org/cryptacular/codec/Base64Encoder.java000066400000000000000000000120731422604312300260700ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.codec; /** * Stateful base 64 encoder with support for configurable line breaks. * * @author Middleware Services */ public class Base64Encoder extends AbstractBaseNEncoder { /** Default base 64 character encoding table. */ private static final char[] DEFAULT_ENCODING_TABLE; /** Filesystem and URL-safe base 64 character encoding table. */ private static final char[] URLSAFE_ENCODING_TABLE; /* Initializes the default character encoding tables. */ static { DEFAULT_ENCODING_TABLE = encodingTable("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/", 64); URLSAFE_ENCODING_TABLE = encodingTable("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_", 64); } /** Creates a new instance that produces base 64-encoded output with no line breaks in the default character set. */ public Base64Encoder() { // Default to no line breaks. this(-1); } /** * Creates a new instance that produces base 64-encoded output with no line breaks and optional URL-safe character * set. * * @param urlSafe True to use URL and filesystem-safe character set, false otherwise. */ public Base64Encoder(final boolean urlSafe) { this(urlSafe, -1); } /** * Creates a new instance that produces base 64-encoded output with the given number of characters per line in the * default character set. * * @param charactersPerLine Number of characters per line. A zero or negative value disables line breaks. */ public Base64Encoder(final int charactersPerLine) { this(false, charactersPerLine); } /** * Creates a new instance that produces base 64-encoded output with the given number of characters per line with the * option of URL-safe character set. * * @param urlSafe True to use URL and filesystem-safe character set, false otherwise. * @param charactersPerLine Number of characters per line. A zero or negative value disables line breaks. */ public Base64Encoder(final boolean urlSafe, final int charactersPerLine) { super(urlSafe ? URLSAFE_ENCODING_TABLE : DEFAULT_ENCODING_TABLE, charactersPerLine); } /** * Creates a new instance that produces base 64-encoded output with the given 64-character alphabet. * * @param alphabet 64-character alphabet to use. */ public Base64Encoder(final String alphabet) { this(alphabet, -1); } /** * Creates a new instance that produces base 64-encoded output with the given 64-character alphabet with line * wrapping at the specified line length; * * @param alphabet 64-character alphabet to use. * @param charactersPerLine Number of characters per line. A zero or negative value disables line breaks. */ public Base64Encoder(final String alphabet, final int charactersPerLine) { super(encodingTable(alphabet, 64), charactersPerLine); } @Override protected int getBlockLength() { return 24; } @Override protected int getBitsPerChar() { return 6; } /** * Builder for base-64 encoders. */ public static class Builder { /** URL-safe alphabet flag. */ private boolean urlSafe; /** Arbitrary alphbet. */ private String alphabet; /** Padding flag. */ private boolean padding; /** Number of base-64 characters per line in output. */ private int charactersPerLine = -1; /** * Sets the URL-safe alphabet flag. * * @param safe True for URL-safe alphabet, false otherwise. * * @return This instance. */ public Base64Encoder.Builder setUrlSafe(final boolean safe) { urlSafe = safe; return this; } /** * Sets an arbitrary 64-character alphabet for encoding. * * @param alpha Alternative alphabet. * * @return This instance. */ public Base64Encoder.Builder setAlphabet(final String alpha) { alphabet = alpha; return this; } /** * Sets padding flag on the encoder. * * @param pad True for base-64 padding, false otherwise. * * @return This instance. */ public Base64Encoder.Builder setPadding(final boolean pad) { padding = pad; return this; } /** * Sets the number of characters per line in output produced by the encoder. * * @param lineLength Number of characters per line. Set to -1 to suppress line breaks. * * @return This instance. */ public Base64Encoder.Builder setCharactersPerLine(final int lineLength) { charactersPerLine = lineLength; return this; } /** * Builds a base-64 encoder with the given options. * * @return New base-64 encoder instance. */ public Base64Encoder build() { final Base64Encoder decoder; if (alphabet != null) { decoder = new Base64Encoder(alphabet, charactersPerLine); } else { decoder = new Base64Encoder(urlSafe, charactersPerLine); } decoder.setPaddedOutput(padding); return decoder; } } } cryptacular-1.2.5/src/main/java/org/cryptacular/codec/Codec.java000066400000000000000000000011161422604312300245550ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.codec; /** * Container for an encoder/decoder pair. * * @author Middleware Services */ public interface Codec { /** @return The byte-to-char encoder of the codec pair. */ Encoder getEncoder(); /** @return The char-to-byte decoder of the codec pair. */ Decoder getDecoder(); /** @return A new instance of the byte-to-char encoder of the codec pair. */ Encoder newEncoder(); /** @return A new instance of the char-to-byte decoder of the codec pair. */ Decoder newDecoder(); } cryptacular-1.2.5/src/main/java/org/cryptacular/codec/Decoder.java000066400000000000000000000025131422604312300251070ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.codec; import java.nio.ByteBuffer; import java.nio.CharBuffer; import org.cryptacular.EncodingException; /** * Describes a potentially stateful character-to-byte decoder. * * @author Middleware Services */ public interface Decoder { /** * Decodes characters in input buffer into bytes placed in the output buffer. This method may be called multiple * times, followed by {@link #finalize(ByteBuffer)}. after all input bytes have been provided. * * @param input Input character buffer. * @param output Output byte buffer. * * @throws EncodingException on decoding errors. */ void decode(CharBuffer input, ByteBuffer output) throws EncodingException; /** * Performs final output decoding (e.g. padding) after all input characters have been provided. * * @param output Output byte buffer. * * @throws EncodingException on decoding errors. */ void finalize(ByteBuffer output) throws EncodingException; /** * Expected number of bytes in the output buffer for an input buffer of the given size. * * @param inputSize Size of input buffer in characters. * * @return Minimum byte buffer size required to store all decoded characters in input buffer. */ int outputSize(int inputSize); } cryptacular-1.2.5/src/main/java/org/cryptacular/codec/Encoder.java000066400000000000000000000025111422604312300251170ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.codec; import java.nio.ByteBuffer; import java.nio.CharBuffer; import org.cryptacular.EncodingException; /** * Describes a potentially stateful byte-to-character encoder. * * @author Middleware Services */ public interface Encoder { /** * Encodes bytes in input buffer into characters placed in the output buffer. This method may be called multiple * times, followed by {@link #finalize(java.nio.CharBuffer)} after all input bytes have been provided. * * @param input Input byte buffer. * @param output Output character buffer. * * @throws EncodingException on encoding errors. */ void encode(ByteBuffer input, CharBuffer output) throws EncodingException; /** * Performs final output encoding (e.g. padding) after all input bytes have been provided. * * @param output Output character buffer. * * @throws EncodingException on encoding errors. */ void finalize(CharBuffer output) throws EncodingException; /** * Expected number of characters in the output buffer for an input buffer of the given size. * * @param inputSize Size of input buffer in bytes. * * @return Minimum character buffer size required to store all encoded input bytes. */ int outputSize(int inputSize); } cryptacular-1.2.5/src/main/java/org/cryptacular/codec/HexCodec.java000066400000000000000000000024161422604312300252260ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.codec; /** * Hexadecimal encoder/decoder pair. * * @author Middleware Services */ public class HexCodec implements Codec { /** Encoder. */ private final Encoder encoder; /** Decoder. */ private final Decoder decoder = new HexDecoder(); /** True to encode in uppercase characters, false otherwise. */ private final boolean uppercase; /** * Creates a new instance that outputs lowercase hex characters and supports decoding in either case. */ public HexCodec() { this(false); } /** * Creates a new instance that optionally outputs uppercase hex characters and supports decoding in either case. * * @param uppercaseOutput True to output uppercase alphabetic characters, false for lowercase. */ public HexCodec(final boolean uppercaseOutput) { uppercase = uppercaseOutput; encoder = new HexEncoder(false, uppercase); } @Override public Encoder getEncoder() { return encoder; } @Override public Decoder getDecoder() { return decoder; } @Override public Encoder newEncoder() { return new HexEncoder(false, uppercase); } @Override public Decoder newDecoder() { return new HexDecoder(); } } cryptacular-1.2.5/src/main/java/org/cryptacular/codec/HexDecoder.java000066400000000000000000000037771422604312300255710ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.codec; import java.nio.ByteBuffer; import java.nio.CharBuffer; import java.util.Arrays; import org.cryptacular.EncodingException; /** * Stateful hexadecimal character-to-byte decoder. * * @author Middleware Services */ public class HexDecoder implements Decoder { /** Hex character decoding table. */ private static final byte[] DECODING_TABLE = new byte[128]; /* Initializes the character decoding table. */ static { Arrays.fill(DECODING_TABLE, (byte) -1); for (int i = 0; i < 10; i++) { DECODING_TABLE[i + 48] = (byte) i; } for (int i = 0; i < 6; i++) { DECODING_TABLE[i + 65] = (byte) (10 + i); DECODING_TABLE[i + 97] = (byte) (10 + i); } } /** Number of encoded characters processed. */ private int count; @Override public void decode(final CharBuffer input, final ByteBuffer output) throws EncodingException { // Ignore leading 0x characters if present if (input.get(0) == '0' && input.get(1) == 'x') { input.position(input.position() + 2); } byte hi = 0; byte lo; char current; while (input.hasRemaining()) { current = input.get(); if (current == ':' || Character.isWhitespace(current)) { continue; } if ((count++ & 0x01) == 0) { hi = lookup(current); } else { lo = lookup(current); output.put((byte) ((hi << 4) | lo)); } } } @Override public void finalize(final ByteBuffer output) throws EncodingException { count = 0; } @Override public int outputSize(final int inputSize) { return inputSize / 2; } /** * Looks up the byte that corresponds to the given character. * * @param c Encoded character. * * @return Decoded byte. */ private static byte lookup(final char c) { final byte b = DECODING_TABLE[c & 0x7F]; if (b < 0) { throw new EncodingException("Invalid hex character " + c); } return b; } } cryptacular-1.2.5/src/main/java/org/cryptacular/codec/HexEncoder.java000066400000000000000000000053451422604312300255740ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.codec; import java.nio.ByteBuffer; import java.nio.CharBuffer; import org.cryptacular.EncodingException; /** * Stateless hexadecimal byte-to-character encoder. * * @author Middleware Services */ public class HexEncoder implements Encoder { /** Lowercase hex character encoding table. */ private static final char[] LC_ENCODING_TABLE = new char[16]; /** Uppercase hex character encoding table. */ private static final char[] UC_ENCODING_TABLE = new char[16]; /* Initializes the encoding character table. */ static { initTable("0123456789abcdef", LC_ENCODING_TABLE); initTable("0123456789ABCDEF", UC_ENCODING_TABLE); } /** Flag indicating whether to delimit every two characters with ':' as in key fingerprints, etc. */ private final boolean delimit; /** Encoding table to use. */ private final char[] table; /** Creates a new instance that does not delimit bytes in the output hex string. */ public HexEncoder() { this(false, false); } /** * Creates a new instance with optional colon-delimiting of bytes. * * @param delimitBytes True to delimit every two characters (i.e. every byte) with ':' character. */ public HexEncoder(final boolean delimitBytes) { this(delimitBytes, false); } /** * Creates a new instance with optional colon-delimiting of bytes and uppercase output. * * @param delimitBytes True to delimit every two characters (i.e. every byte) with ':' character. * @param uppercase True to output uppercase alphabetic characters, false for lowercase. */ public HexEncoder(final boolean delimitBytes, final boolean uppercase) { delimit = delimitBytes; table = uppercase ? UC_ENCODING_TABLE : LC_ENCODING_TABLE; } @Override public void encode(final ByteBuffer input, final CharBuffer output) throws EncodingException { byte current; while (input.hasRemaining()) { current = input.get(); output.put(table[(current & 0xf0) >> 4]); output.put(table[current & 0x0f]); if (delimit && input.hasRemaining()) { output.put(':'); } } } @Override public void finalize(final CharBuffer output) throws EncodingException {} @Override public int outputSize(final int inputSize) { int size = inputSize * 2; if (delimit) { size += inputSize - 1; } return size; } /** * Initializes the encoding table for the given character set. * * @param charset Character set. * @param table Encoding table. */ private static void initTable(final String charset, final char[] table) { for (int i = 0; i < charset.length(); i++) { table[i] = charset.charAt(i); } } } cryptacular-1.2.5/src/main/java/org/cryptacular/generator/000077500000000000000000000000001422604312300236075ustar00rootroot00000000000000cryptacular-1.2.5/src/main/java/org/cryptacular/generator/AbstractOTPGenerator.java000066400000000000000000000047151422604312300304560ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.generator; import org.bouncycastle.crypto.Digest; import org.bouncycastle.crypto.macs.HMac; import org.bouncycastle.crypto.params.KeyParameter; import org.cryptacular.util.ByteUtil; /** * Abstract base class for HOTP and TOTP OTP generation schemes. * * @author Middleware Services */ public abstract class AbstractOTPGenerator { /** Array of modulus values indexed per number of digits in OTP output. */ private static final int[] MODULUS = new int[] { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000, }; /** Number of digits in generated OTP. */ private int numberOfDigits = 6; /** @return Number of digits in generated OTP. */ public int getNumberOfDigits() { return numberOfDigits; } /** * Sets the numbers in the generated OTP. * * @param digits Number of digits in generated OTP. MUST be in the range 6 - 9. Default is 6. */ public void setNumberOfDigits(final int digits) { if (digits < 6 || digits > 9) { throw new IllegalArgumentException("Number of generated digits must be in range 6-9."); } this.numberOfDigits = digits; } /** * Internal OTP generation method. * * @param key Per-user key. * @param count Counter moving factor. * * @return Integer OTP. */ protected int generateInternal(final byte[] key, final long count) { final HMac hmac = new HMac(getDigest()); final byte[] output = new byte[hmac.getMacSize()]; hmac.init(new KeyParameter(key)); hmac.update(ByteUtil.toBytes(count), 0, 8); hmac.doFinal(output, 0); return truncate(output) % MODULUS[numberOfDigits]; } /** @return Digest algorithm used for HMAC operation. */ protected abstract Digest getDigest(); /** * Truncates HMAC output onto an unsigned (i.e. 31-bit) integer using the strategy discussed in RFC 4226, * section 5.3. * * @param hmac HMAC output. * * @return Truncated output. */ private int truncate(final byte[] hmac) { // Offset is the lowest 4 bits of the computed hash final int offset = hmac[hmac.length - 1] & 0xf; return (hmac[offset] & 0x7f) << 24 | (hmac[offset + 1] & 0xff) << 16 | (hmac[offset + 2] & 0xff) << 8 | (hmac[offset + 3] & 0xff); } } cryptacular-1.2.5/src/main/java/org/cryptacular/generator/HOTPGenerator.java000066400000000000000000000014441422604312300270760ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.generator; import org.bouncycastle.crypto.Digest; import org.bouncycastle.crypto.digests.SHA1Digest; /** * OTP generator component that implements the HOTP scheme described in * RFC 4226. * * @author Middleware Services */ public class HOTPGenerator extends AbstractOTPGenerator { /** * Generates the OTP given a per-user key and invocation count. * * @param key Per-user key. * @param count Counter moving factor. * * @return Integer OTP. */ public int generate(final byte[] key, final long count) { return generateInternal(key, count); } @Override protected Digest getDigest() { return new SHA1Digest(); } } cryptacular-1.2.5/src/main/java/org/cryptacular/generator/IdGenerator.java000066400000000000000000000005051422604312300266550ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.generator; /** * Generation strategy for random identifiers. * * @author Middleware Services */ public interface IdGenerator { /** * Generates a random identifier. * * @return Random identifier. */ String generate(); } cryptacular-1.2.5/src/main/java/org/cryptacular/generator/KeyPairGenerator.java000066400000000000000000000057121422604312300276720ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.generator; import java.security.InvalidAlgorithmParameterException; import java.security.KeyPair; import java.security.SecureRandom; import org.bouncycastle.jce.spec.ECNamedCurveGenParameterSpec; /** * Static factory that generates various types of asymmetric key pairs. * * @author Middleware Services */ public final class KeyPairGenerator { /** Private constructor of static factory. */ private KeyPairGenerator() {} /** * Generates a DSA key pair. * * @param random Random source required for key generation. * @param bitLength Desired key size in bits. * * @return DSA key pair of desired size. */ public static KeyPair generateDSA(final SecureRandom random, final int bitLength) { final org.bouncycastle.jcajce.provider.asymmetric.dsa.KeyPairGeneratorSpi generator = new org.bouncycastle.jcajce.provider.asymmetric.dsa.KeyPairGeneratorSpi(); generator.initialize(bitLength, random); return generator.generateKeyPair(); } /** * Generates a RSA key pair. * * @param random Random source required for key generation. * @param bitLength Desired key size in bits. * * @return RSA key pair of desired size. */ public static KeyPair generateRSA(final SecureRandom random, final int bitLength) { final org.bouncycastle.jcajce.provider.asymmetric.rsa.KeyPairGeneratorSpi generator = new org.bouncycastle.jcajce.provider.asymmetric.rsa.KeyPairGeneratorSpi(); generator.initialize(bitLength, random); return generator.generateKeyPair(); } /** * Generates a EC key pair. * * @param random Random source required for key generation. * @param bitLength Desired key size in bits. * * @return EC key pair of desired size. */ public static KeyPair generateEC(final SecureRandom random, final int bitLength) { final org.bouncycastle.jcajce.provider.asymmetric.ec.KeyPairGeneratorSpi.EC generator = new org.bouncycastle.jcajce.provider.asymmetric.ec.KeyPairGeneratorSpi.EC(); generator.initialize(bitLength, random); return generator.generateKeyPair(); } /** * Generates a EC key pair. * * @param random Random source required for key generation. * @param namedCurve Well-known elliptic curve name that includes domain parameters including key size. * * @return EC key pair according to named curve. */ public static KeyPair generateEC(final SecureRandom random, final String namedCurve) { final org.bouncycastle.jcajce.provider.asymmetric.ec.KeyPairGeneratorSpi.EC generator = new org.bouncycastle.jcajce.provider.asymmetric.ec.KeyPairGeneratorSpi.EC(); try { generator.initialize(new ECNamedCurveGenParameterSpec(namedCurve), random); } catch (InvalidAlgorithmParameterException e) { throw new IllegalArgumentException("Invalid EC curve " + namedCurve, e); } return generator.generateKeyPair(); } } cryptacular-1.2.5/src/main/java/org/cryptacular/generator/LimitException.java000066400000000000000000000010431422604312300274050ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.generator; /** * Runtime exception that describes a condition where some fundamental limit imposed by the implementation or * specification of a generator has been exceeded. * * @author Middleware Services */ public class LimitException extends RuntimeException { /** * Creates a new instance with the given error description.. * * @param message Error message. */ public LimitException(final String message) { super(message); } } cryptacular-1.2.5/src/main/java/org/cryptacular/generator/Nonce.java000066400000000000000000000007751422604312300255250ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.generator; /** * Nonce generation strategy. * * @author Middleware Services */ public interface Nonce { /** * Generates a nonce value. * * @return Nonce bytes. * * @throws LimitException When a limit imposed by the nonce generation strategy, if any, is exceeded. */ byte[] generate() throws LimitException; /** @return Length in bytes of generated nonce values. */ int getLength(); } cryptacular-1.2.5/src/main/java/org/cryptacular/generator/RandomIdGenerator.java000066400000000000000000000037361422604312300300270ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.generator; import java.security.SecureRandom; /** * Generates random identifiers with an alphanumeric character set by default. * * @author Middleware Services */ public class RandomIdGenerator implements IdGenerator { /** Default character set. */ public static final String DEFAULT_CHARSET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; /** Size of generated identifiers. */ private final int length; /** Identifier character set. */ private final String charset; /** Source of randomness. */ private final SecureRandom secureRandom; /** * Creates a new instance with the default character set. * * @param length Number of characters in generated identifiers. */ public RandomIdGenerator(final int length) { this(length, DEFAULT_CHARSET); } /** * Creates a new instance with a defined character set. * * @param length Number of characters in generated identifiers. * @param charset Character set. */ public RandomIdGenerator(final int length, final String charset) { if (length < 1) { throw new IllegalArgumentException("Length must be positive"); } this.length = length; if (charset == null || charset.length() < 2 || charset.length() > 128) { throw new IllegalArgumentException("Charset length must be in the range 2 - 128"); } this.charset = charset; secureRandom = new SecureRandom(); // Call nextBytes to force seeding via default process secureRandom.nextBytes(new byte[1]); } @Override public String generate() { final StringBuilder id = new StringBuilder(length); final byte[] output = new byte[length]; secureRandom.nextBytes(output); int index; for (int i = 0; i < output.length && id.length() < length; i++) { index = 0x7F & output[i]; id.append(charset.charAt(index % charset.length())); } return id.toString(); } } cryptacular-1.2.5/src/main/java/org/cryptacular/generator/SecretKeyGenerator.java000066400000000000000000000041341422604312300302210ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.generator; import java.security.SecureRandom; import javax.crypto.SecretKey; import javax.crypto.spec.SecretKeySpec; import org.bouncycastle.crypto.BlockCipher; import org.bouncycastle.crypto.digests.SHA256Digest; import org.bouncycastle.crypto.prng.SP800SecureRandomBuilder; import org.cryptacular.util.NonceUtil; /** * Factory class with static methods for generating {@link SecretKey}s. * * @author Middleware Services */ public final class SecretKeyGenerator { /** Private constructor of static class. */ private SecretKeyGenerator() {} /** * Generates a symmetric encryption key whose size is equal to the cipher block size. * * @param cipher Cipher with with key will be used. * * @return Symmetric encryption key. */ public static SecretKey generate(final BlockCipher cipher) { return generate(cipher.getBlockSize() * 8, cipher); } /** * Generates a symmetric encryption key of the given length. * * @param bitLength Desired key length in bits. * @param cipher Cipher with with key will be used. * * @return Symmetric encryption key. */ public static SecretKey generate(final int bitLength, final BlockCipher cipher) { // Want as much nonce data as key bits final byte[] nonce = NonceUtil.randomNonce((bitLength + 7) / 8); return generate(bitLength, cipher, new SP800SecureRandomBuilder().buildHash(new SHA256Digest(), nonce, false)); } /** * Generates a symmetric encryption key of the given length. * * @param bitLength Desired key length in bits. * @param cipher Cipher with with key will be used. * @param random Randomness provider for key generation. * * @return Symmetric encryption key. */ public static SecretKey generate(final int bitLength, final BlockCipher cipher, final SecureRandom random) { // Round up for bit lengths that are not a multiple of 8 final byte[] key = new byte[(bitLength + 7) / 8]; random.nextBytes(key); return new SecretKeySpec(key, cipher.getAlgorithmName()); } } cryptacular-1.2.5/src/main/java/org/cryptacular/generator/TOTPGenerator.java000066400000000000000000000070321422604312300271110ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.generator; import org.bouncycastle.crypto.Digest; import org.cryptacular.spec.DigestSpec; import org.cryptacular.spec.Spec; /** * OTP generator component that implements the TOTP scheme described in * RFC 6238. * * @author Middleware Services */ public class TOTPGenerator extends AbstractOTPGenerator { /** Digest algorithm specification. */ private Spec digestSpecification = new DigestSpec("SHA1"); /** * Current system time in seconds since the start of the epoch, 1970-01-01T00:00:00. * This value is used if and only if it is a non-negative value; otherwise the current system time is used. */ private long currentTime = -1; /** Reference start time, T0. Default 0, i.e. 1970-01-01T00:00:00. */ private int startTime; /** Time step in seconds, X. Default is 30 seconds. */ private int timeStep = 30; /** @return Digest algorithm used with the HMAC function. */ public Spec getDigestSpecification() { return digestSpecification; } /** * Sets the digest algorithm used with the HMAC function. * * @param specification SHA-1, SHA-256, or SHA-512 digest specification. */ public void setDigestSpecification(final Spec specification) { if ("SHA1".equalsIgnoreCase(specification.getAlgorithm()) || "SHA-1".equalsIgnoreCase(specification.getAlgorithm()) || "SHA256".equalsIgnoreCase(specification.getAlgorithm()) || "SHA-256".equalsIgnoreCase(specification.getAlgorithm()) || "SHA512".equalsIgnoreCase(specification.getAlgorithm()) || "SHA-512".equalsIgnoreCase(specification.getAlgorithm())) { this.digestSpecification = specification; return; } throw new IllegalArgumentException("Unsupported digest algorithm " + specification); } /** @return Reference start time. */ public int getStartTime() { return startTime; } /** * Sets the reference start time, T0. Default 0, i.e. 1970-01-01T00:00:00. * * @param seconds Start time in seconds. */ public void setStartTime(final int seconds) { this.startTime = seconds; } /** @return Time step in seconds. */ public int getTimeStep() { return timeStep; } /** * Sets the time step, X. * * @param seconds Time step in seconds. Default is 30. This value determines the validity window of generated OTP * values. */ public void setTimeStep(final int seconds) { this.timeStep = seconds; } /** * Generates the OTP given a per-user key. * * @param key Per-user key. * * @return Integer OTP. */ public int generate(final byte[] key) { final long t = (currentTime() - startTime) / timeStep; return generateInternal(key, t); } @Override protected Digest getDigest() { return digestSpecification.newInstance(); } /** * Sets the current time (supports testing). This value is used if and only if it is a non-negative value; otherwise * the current system time is used. * * @param epochSeconds Seconds since the start of the epoch, 1970-01-01T00:00:00. */ protected void setCurrentTime(final long epochSeconds) { currentTime = epochSeconds; } /** * @return Current system time in seconds since the start of epoch, 1970-01-01T00:00:00. */ protected long currentTime() { if (currentTime >= 0) { return currentTime; } return System.currentTimeMillis() / 1000; } } cryptacular-1.2.5/src/main/java/org/cryptacular/generator/sp80038a/000077500000000000000000000000001422604312300247755ustar00rootroot00000000000000cryptacular-1.2.5/src/main/java/org/cryptacular/generator/sp80038a/BigIntegerCounterNonce.java000066400000000000000000000034251422604312300322060ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.generator.sp80038a; import java.math.BigInteger; import java.util.Arrays; import org.cryptacular.generator.LimitException; import org.cryptacular.generator.Nonce; /** * Uses a {@link BigInteger} to back a counter in order to produce nonces of arbitrary length. * *

A common use case for this component is creation of IVs for ciphers with 16-byte block size, e.g. AES.

* *

Instances of this class are thread safe.

* * @author Middleware Services */ public class BigIntegerCounterNonce implements Nonce { /** Counter. */ private BigInteger counter; /** Length of generated counter nonce values in bytes. */ private final int length; /** * Creates a new instance with given parameters. * * @param counter Initial counter value. * @param length Maximum length of generated counter values in bytes. */ public BigIntegerCounterNonce(final BigInteger counter, final int length) { if (length < 1) { throw new IllegalArgumentException("Length must be positive"); } this.length = length; this.counter = counter; } @Override public byte[] generate() throws LimitException { final byte[] value; synchronized (this) { counter = counter.add(BigInteger.ONE); value = counter.toByteArray(); } if (value.length > length) { throw new LimitException("Counter value exceeded max byte length " + length); } if (value.length < length) { final byte[] temp = new byte[length]; Arrays.fill(temp, (byte) 0); System.arraycopy(value, 0, temp, temp.length - value.length, value.length); return temp; } return value; } @Override public int getLength() { return length; } } cryptacular-1.2.5/src/main/java/org/cryptacular/generator/sp80038a/EncryptedNonce.java000066400000000000000000000035331422604312300305640ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.generator.sp80038a; import javax.crypto.SecretKey; import org.bouncycastle.crypto.BlockCipher; import org.bouncycastle.crypto.params.KeyParameter; import org.cryptacular.generator.LimitException; import org.cryptacular.generator.Nonce; import org.cryptacular.spec.Spec; import org.cryptacular.util.NonceUtil; /** * Nonce generation strategy that produces a random value according to NIST * SP-800-38a, appendix C, method 1 (encrypted nonce), suitable for use with any block cipher mode described in that * standard except OFB. * *

Instances of this class are thread safe.

* * @author Middleware Services */ public class EncryptedNonce implements Nonce { /** Block cipher. */ private final BlockCipher cipher; /** Encryption key. */ private final SecretKey key; /** * Creates a new instance. * * @param cipherSpec Block cipher specification. * @param key Symmetric key. */ public EncryptedNonce(final Spec cipherSpec, final SecretKey key) { this(cipherSpec.newInstance(), key); } /** * Creates a new instance. * * @param cipher Block cipher to use. * @param key Symmetric key. */ public EncryptedNonce(final BlockCipher cipher, final SecretKey key) { this.cipher = cipher; this.key = key; } @Override public byte[] generate() throws LimitException { final byte[] result = new byte[cipher.getBlockSize()]; final byte[] nonce = NonceUtil.randomNonce(result.length); synchronized (cipher) { cipher.init(true, new KeyParameter(key.getEncoded())); cipher.processBlock(nonce, 0, result, 0); cipher.reset(); } return result; } @Override public int getLength() { return cipher.getBlockSize(); } } cryptacular-1.2.5/src/main/java/org/cryptacular/generator/sp80038a/LongCounterNonce.java000066400000000000000000000023241422604312300310630ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.generator.sp80038a; import java.util.concurrent.atomic.AtomicLong; import org.cryptacular.generator.LimitException; import org.cryptacular.generator.Nonce; import org.cryptacular.util.ByteUtil; /** * Simple counter nonce that uses a long integer counter internally and produces 8-byte nonces. Note that this component * is suitable exclusively for ciphers with block length 8, e.g. Blowfish. * *

Instances of this class are thread safe.

* * @author Middleware Services * @see BigIntegerCounterNonce */ public class LongCounterNonce implements Nonce { /** Counter. */ private final AtomicLong counter; /** Creates a new instance whose counter values start at 1. */ public LongCounterNonce() { this(0); } /** * Creates a new instance whose counter values start above the given value. * * @param start Start value. */ public LongCounterNonce(final long start) { counter = new AtomicLong(start); } @Override public byte[] generate() throws LimitException { return ByteUtil.toBytes(counter.incrementAndGet()); } @Override public int getLength() { return 8; } } cryptacular-1.2.5/src/main/java/org/cryptacular/generator/sp80038a/RBGNonce.java000066400000000000000000000030561422604312300272410ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.generator.sp80038a; import org.bouncycastle.crypto.prng.drbg.SP80090DRBG; import org.cryptacular.generator.LimitException; import org.cryptacular.generator.Nonce; import org.cryptacular.util.NonceUtil; /** * Nonce generation strategy that produces a random value according to NIST * SP-800-38a, appendix C, method 2 (random number generator), suitable for use with any block cipher mode described * in that standard except OFB. * *

Instances of this class are thread safe.

* * @author Middleware Services */ public class RBGNonce implements Nonce { /** Length of generated nonces. */ private final int length; /** Random bit generator. */ private final SP80090DRBG rbg; /** Creates a new instance that produces 16-bytes (128-bits) of random data. */ public RBGNonce() { this(16); } /** * Creates a new instance that produces length bytes of random data. * * @param length Number of bytes in generated nonce values. */ public RBGNonce(final int length) { if (length < 1) { throw new IllegalArgumentException("Length must be positive"); } this.length = length; this.rbg = NonceUtil.newRBG(length); } @Override public byte[] generate() throws LimitException { final byte[] random = new byte[length]; synchronized (rbg) { rbg.generate(random, null, false); } return random; } @Override public int getLength() { return length; } } cryptacular-1.2.5/src/main/java/org/cryptacular/generator/sp80038d/000077500000000000000000000000001422604312300250005ustar00rootroot00000000000000cryptacular-1.2.5/src/main/java/org/cryptacular/generator/sp80038d/CounterNonce.java000066400000000000000000000107211422604312300302460ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.generator.sp80038d; import java.util.concurrent.atomic.AtomicLong; import org.cryptacular.generator.LimitException; import org.cryptacular.generator.Nonce; import org.cryptacular.util.ByteUtil; /** * Deterministic nonce generation strategy that uses a counter for the invocation field as described in NIST SP-800-38D, section 8.2.1. The * invocation part of the sequence is always 64 bits (8 bytes) due to the use of a long, thus the length of * the nonce is determined by the length of the fixed part: length = 8 + fixed.length. * *

NOTE: users of this class are responsible for maintaining the invocation count in order to * support enforcement of constraints described in section 8.3; namely the following:

* *
The total number of invocations of the authenticated encryption function shall not exceed 232, * including all IV lengths and all instances of the authenticated encryption function with the given key.
* *

Instances of this class enforce this constraint by considering the nonce length, which determines whether the * constraint applies, and the invocation count. The invocation count is incremented upon every invocation of {@link * #generate()} method. The current invocation count is accessible via {@link #getInvocations()}.

* *

Instances of this class are thread safe.

* * @author Middleware Services */ public class CounterNonce implements Nonce { /** Default nonce getLength is {@value} bytes. */ public static final int DEFAULT_LENGTH = 12; /** * Maximum invocations is 232. Does not apply to nonces with default getLength, {@value #DEFAULT_LENGTH}. */ public static final long MAX_INVOCATIONS = 0xFFFFFFFFL; /** Fixed field value. */ private final byte[] fixed; /** Invocation count. */ private final AtomicLong count; /** * Creates a new instance. * * @param fixed User-defined fixed field value. * @param invocations Initial invocation count. The invocations field is incremented _before_ use in {@link * #generate()}. */ public CounterNonce(final String fixed, final long invocations) { this(ByteUtil.toBytes(fixed), invocations); } /** * Creates a new instance. Instances of this method produces nonces of the default length, {@value #DEFAULT_LENGTH}, * and are not subject to constraints on the number of invocations. * * @param fixed User-defined fixed field value. * @param invocations Initial invocation count. The invocations field is incremented _before_ use in {@link * #generate()}. */ public CounterNonce(final int fixed, final long invocations) { this(ByteUtil.toBytes(fixed), invocations); } /** * Creates a new instance. * * @param fixed User-defined fixed field value. * @param invocations Initial invocation count. The invocations field is incremented _before_ use in {@link * #generate()}. */ public CounterNonce(final long fixed, final long invocations) { this(ByteUtil.toBytes(fixed), invocations); } /** * Creates a new instance. * * @param fixed User-defined fixed field value. * @param invocations Initial invocation count. The invocations field is incremented _before_ use in {@link * #generate()}. */ public CounterNonce(final byte[] fixed, final long invocations) { if (fixed == null || fixed.length == 0) { throw new IllegalArgumentException("Fixed part cannot be null or empty."); } this.count = new AtomicLong(invocations); this.fixed = fixed; } @Override public byte[] generate() throws LimitException { final byte[] value = new byte[getLength()]; System.arraycopy(fixed, 0, value, 0, fixed.length); final long next = count.incrementAndGet(); if (value.length != DEFAULT_LENGTH) { // Enforce constraints described in section 8.3 if (next > MAX_INVOCATIONS) { throw new LimitException("Exceeded 2^32 invocations."); } } ByteUtil.toBytes(next, value, fixed.length); return value; } @Override public int getLength() { return fixed.length + 8; } /** @return Current invocation count. */ public long getInvocations() { return count.get(); } } cryptacular-1.2.5/src/main/java/org/cryptacular/generator/sp80038d/RBGNonce.java000066400000000000000000000066661422604312300272560ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.generator.sp80038d; import org.bouncycastle.crypto.digests.SHA256Digest; import org.bouncycastle.crypto.prng.drbg.HashSP800DRBG; import org.bouncycastle.crypto.prng.drbg.SP80090DRBG; import org.cryptacular.generator.LimitException; import org.cryptacular.generator.Nonce; import org.cryptacular.util.ByteUtil; import org.cryptacular.util.NonceUtil; /** * RBG-based nonce generation strategy that uses a RBG component to produce values for the invocation field as described * in NIST SP-800-38D, section 8.2.2. * *

NOTE: users of this class are responsible for counting number of invocations and enforcing the * constraints described in section 8.3; namely the following:

* *
The total number of invocations of the authenticated encryption function shall not exceed 232, * including all IV lengths and all instances of the authenticated encryption function with the given key.
* *

Instances of this class are thread safe.

* * @author Middleware Services */ public class RBGNonce implements Nonce { /** Fixed field value. */ private final byte[] fixed; /** Number of bytes of random data in invocation field. */ private final int randomLength; /** Random bit generator. */ private final SP80090DRBG rbg; /** * Creates a new instance that produces 12-bytes (96-bits) of random data; that is, the fixed field of the nonce is * null. */ public RBGNonce() { this(12); } /** * Creates a new instance that produces length bytes of random data; that is, the fixed field of the nonce is null. * * @param randomLength Number of bytes in the random part of the nonce. MUST be at least 12. */ public RBGNonce(final int randomLength) { this(null, randomLength); } /** * Creates a new instance using the given fixed field value. * * @param fixed User-defined fixed field value. * @param randomLength Number of bytes in the random part of the nonce. MUST be at least 12. */ public RBGNonce(final String fixed, final int randomLength) { if (randomLength < 12) { throw new IllegalArgumentException("Must specify at least 12 bytes (96 bits) for random part."); } this.randomLength = randomLength; if (fixed != null) { this.fixed = ByteUtil.toBytes(fixed); } else { this.fixed = new byte[0]; } this.rbg = newRBG(this.randomLength, this.fixed); } @Override public byte[] generate() throws LimitException { final byte[] random = new byte[randomLength]; synchronized (rbg) { rbg.generate(random, null, false); } final byte[] value = new byte[getLength()]; System.arraycopy(fixed, 0, value, 0, fixed.length); System.arraycopy(random, 0, value, fixed.length, random.length); return value; } @Override public int getLength() { return fixed.length + randomLength; } /** * Creates a new DRBG instance. * * @param length Length in bits of values produced by DRBG. * @param domain Domain qualifier. * * @return New DRBG instance. */ private static SP80090DRBG newRBG(final int length, final byte[] domain) { return new HashSP800DRBG( new SHA256Digest(), length, NonceUtil.randomEntropySource(length), domain, NonceUtil.timestampNonce(8)); } } cryptacular-1.2.5/src/main/java/org/cryptacular/io/000077500000000000000000000000001422604312300222305ustar00rootroot00000000000000cryptacular-1.2.5/src/main/java/org/cryptacular/io/ChunkHandler.java000066400000000000000000000014551422604312300254460ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.io; import java.io.IOException; import java.io.OutputStream; /** * Callback interface that supports arbitrary processing of data chunks read from an input stream. * * @author Middleware Services */ public interface ChunkHandler { /** * Processes the given chunk of data and writes it to the output stream. * * @param input Chunk of input data to process. * @param offset Offset into input array where data to process starts. * @param count Number of bytes of input data to process. * @param output Output stream where processed data is written. * * @throws IOException On IO errors. */ void handle(byte[] input, int offset, int count, OutputStream output) throws IOException; } cryptacular-1.2.5/src/main/java/org/cryptacular/io/ClassPathResource.java000066400000000000000000000030511422604312300264640ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.io; import java.io.InputStream; /** * Resource that produces a {@link InputStream} from a classpath resource. * * @author Middleware Services */ public class ClassPathResource implements Resource { /** Classpath location of resource. */ private final String classPath; /** Class loader used to get input streams on classpath locations. */ private final ClassLoader classLoader; /** * Creates a new resource that reads from the given classpath location. * Thread.currentThread().getContextClassLoader() is used to obtain the class loader used to obtain an input * stream on the given classpath. * * @param path Classpath location. */ public ClassPathResource(final String path) { this(path, Thread.currentThread().getContextClassLoader()); } /** * Creates a new resource that reads from the given classpath location. * * @param path Classpath location. * @param loader Class loader used to obtain an input stream on the given classpath location. */ public ClassPathResource(final String path, final ClassLoader loader) { // Strip leading / since absolute paths are not supported by // ClassLoader#getResourceAsStream(...) if (path.startsWith("/")) { this.classPath = path.substring(1); } else { this.classPath = path; } this.classLoader = loader; } @Override public InputStream getInputStream() { return classLoader.getResourceAsStream(classPath); } } cryptacular-1.2.5/src/main/java/org/cryptacular/io/DecodingInputStream.java000066400000000000000000000065201422604312300270060ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.io; import java.io.FilterInputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.nio.ByteBuffer; import java.nio.CharBuffer; import org.cryptacular.codec.Base64Decoder; import org.cryptacular.codec.Decoder; import org.cryptacular.codec.HexDecoder; /** * Filters read bytes through a {@link Decoder} such that consumers obtain raw (decoded) bytes from read operations. * * @author Middleware Services */ public class DecodingInputStream extends FilterInputStream { /** Performs decoding. */ private final Decoder decoder; /** Wraps the input stream to convert bytes to characters. */ private final InputStreamReader reader; /** Holds input bytes as characters. */ private CharBuffer input; /** Receives decoding result. */ private ByteBuffer output; /** * Creates a new instance that wraps the given stream and performs decoding using the given encoder component. * * @param in Input stream to wrap. * @param d Decoder that provides on-the-fly decoding. */ public DecodingInputStream(final InputStream in, final Decoder d) { super(in); if (d == null) { throw new IllegalArgumentException("Decoder cannot be null."); } decoder = d; reader = new InputStreamReader(in); } @Override public int read() throws IOException { return read(new byte[1]); } @Override public int read(final byte[] b) throws IOException { return read(b, 0, b.length); } @Override public int read(final byte[] b, final int off, final int len) throws IOException { prepareInputBuffer(len - off); prepareOutputBuffer(); if (reader.read(input) < 0) { decoder.finalize(output); if (output.position() == 0) { return -1; } } else { input.flip(); decoder.decode(input, output); } output.flip(); output.get(b, off, output.limit()); return output.position(); } /** * Creates a new instance that decodes base64 input from the given stream. * * @param in Wrapped input stream. * * @return Decoding input stream that decodes base64 output. */ public static DecodingInputStream base64(final InputStream in) { return new DecodingInputStream(in, new Base64Decoder()); } /** * Creates a new instance that decodes hexadecimal input from the given stream. * * @param in Wrapped input stream. * * @return Decoding input stream that decodes hexadecimal output. */ public static DecodingInputStream hex(final InputStream in) { return new DecodingInputStream(in, new HexDecoder()); } /** * Prepares the input buffer to receive the given number of bytes. * * @param required Number of bytes required. */ private void prepareInputBuffer(final int required) { if (input == null || input.capacity() < required) { input = CharBuffer.allocate(required); } else { input.clear(); } } /** Prepares the output buffer based on input buffer capacity. */ private void prepareOutputBuffer() { final int required = decoder.outputSize(input.capacity()); if (output == null || output.capacity() < required) { output = ByteBuffer.allocate(required); } else { output.clear(); } } } cryptacular-1.2.5/src/main/java/org/cryptacular/io/DirectByteArrayOutputStream.java000066400000000000000000000015451422604312300305320ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.io; import java.io.ByteArrayOutputStream; /** * Extends {@link ByteArrayOutputStream} by allowing direct access to the internal byte buffer. * * @author Middleware Services */ public class DirectByteArrayOutputStream extends ByteArrayOutputStream { /** Creates a new instance with a buffer of the default size. */ public DirectByteArrayOutputStream() { super(); } /** * Creates a new instance with a buffer of the given initial capacity. * * @param capacity Initial capacity of internal buffer. */ public DirectByteArrayOutputStream(final int capacity) { super(capacity); } /** * Gets the internal byte buffer. * * @return Internal buffer that holds written bytes. */ public byte[] getBuffer() { return buf; } } cryptacular-1.2.5/src/main/java/org/cryptacular/io/EncodingOutputStream.java000066400000000000000000000074321422604312300272240ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.io; import java.io.FilterOutputStream; import java.io.IOException; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.nio.ByteBuffer; import java.nio.CharBuffer; import org.cryptacular.codec.Base64Encoder; import org.cryptacular.codec.Encoder; import org.cryptacular.codec.HexEncoder; /** * Filters written bytes through an {@link Encoder} such that encoded data is written to the underlying output stream. * * @author Middleware Services */ public class EncodingOutputStream extends FilterOutputStream { /** Performs decoding. */ private final Encoder encoder; /** Wraps the output stream to convert characters to bytes. */ private final OutputStreamWriter writer; /** Receives encoding result. */ private CharBuffer output; /** * Creates a new instance that wraps the given stream and performs encoding using the given encoder component. * * @param out Output stream to wrap. * @param e Encoder that provides on-the-fly encoding. */ public EncodingOutputStream(final OutputStream out, final Encoder e) { super(out); if (e == null) { throw new IllegalArgumentException("Encoder cannot be null."); } encoder = e; writer = new OutputStreamWriter(out); } @Override public void write(final int b) throws IOException { write(new byte[] {(byte) b}); } @Override public void write(final byte[] b) throws IOException { write(b, 0, b.length); } @Override public void write(final byte[] b, final int off, final int len) throws IOException { final ByteBuffer input = ByteBuffer.wrap(b, off, len); final int required = encoder.outputSize(len - off); if (output == null || output.capacity() < required) { output = CharBuffer.allocate(required); } else { output.clear(); } encoder.encode(input, output); output.flip(); writer.write(output.toString()); writer.flush(); } @Override public void flush() throws IOException { writer.flush(); } @Override public void close() throws IOException { if (output == null) { output = CharBuffer.allocate(8); } else { output.clear(); } encoder.finalize(output); output.flip(); writer.write(output.toString()); writer.flush(); writer.close(); } /** * Creates a new instance that produces base64 output in the given stream. * *

NOTE: there are no line breaks in the output with this version.

* * @param out Wrapped output stream. * * @return Encoding output stream that produces base64 output. */ public static EncodingOutputStream base64(final OutputStream out) { return base64(out, -1); } /** * Creates a new instance that produces base64 output in the given stream. * *

NOTE: this version supports output with configurable line breaks.

* * @param out Wrapped output stream. * @param lineLength Length of each base64-encoded line in output. A zero or negative value disables line breaks. * * @return Encoding output stream that produces base64 output. */ public static EncodingOutputStream base64(final OutputStream out, final int lineLength) { return new EncodingOutputStream(out, new Base64Encoder(lineLength)); } /** * Creates a new instance that produces hexadecimal output in the given stream. * *

NOTE: there are no line breaks in the output.

* * @param out Wrapped output stream. * * @return Encoding output stream that produces hexadecimal output. */ public static EncodingOutputStream hex(final OutputStream out) { return new EncodingOutputStream(out, new HexEncoder()); } } cryptacular-1.2.5/src/main/java/org/cryptacular/io/FileResource.java000066400000000000000000000016451422604312300254700ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.io; import java.io.BufferedInputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; /** * Resource that produces a buffered {@link FileInputStream} from a file. * * @author Middleware Services */ public class FileResource implements Resource { /** Underlying file resource. */ private File file; /** * Creates a new file resource. * * @param file Non-null file. */ public FileResource(final File file) { if (file == null) { throw new IllegalArgumentException("File cannot be null."); } this.file = file; } @Override public InputStream getInputStream() throws IOException { return new BufferedInputStream(new FileInputStream(file)); } @Override public String toString() { return file.toString(); } } cryptacular-1.2.5/src/main/java/org/cryptacular/io/Resource.java000066400000000000000000000015751422604312300246720ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.io; import java.io.IOException; import java.io.InputStream; /** * Resource descriptor that provides a strategy to get an {@link InputStream} to read bytes. * * @author Middleware Services */ public interface Resource { /** * Gets an input stream around the resource. Callers of this method are responsible for resource cleanup; it should be * sufficient to simply call {@link java.io.InputStream#close()} unless otherwise noted. * *

Implementers should produce a new instance on every call to this method to provide for thread-safe usage * patterns on a shared resource.

* * @return Input stream around underlying resource, e.g. file, remote resource (URI), etc. * * @throws IOException On IO errors. */ InputStream getInputStream() throws IOException; } cryptacular-1.2.5/src/main/java/org/cryptacular/io/URLResource.java000066400000000000000000000014741422604312300252530ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.io; import java.io.IOException; import java.io.InputStream; import java.net.URL; /** * Describes a (presumably remote) resource accessible via URL. * * @author Middleware Services */ public class URLResource implements Resource { /** Location of resource. */ private URL url; /** * Creates a new URL resource. * * @param url Non-null URL where resource is located. */ public URLResource(final URL url) { if (url == null) { throw new IllegalArgumentException("URL cannot be null."); } this.url = url; } @Override public InputStream getInputStream() throws IOException { return url.openStream(); } @Override public String toString() { return url.toString(); } } cryptacular-1.2.5/src/main/java/org/cryptacular/pbe/000077500000000000000000000000001422604312300223675ustar00rootroot00000000000000cryptacular-1.2.5/src/main/java/org/cryptacular/pbe/AbstractEncryptionScheme.java000066400000000000000000000062661422604312300302070ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.pbe; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.Arrays; import org.bouncycastle.crypto.BufferedBlockCipher; import org.bouncycastle.crypto.CipherParameters; import org.bouncycastle.crypto.InvalidCipherTextException; import org.bouncycastle.crypto.io.CipherInputStream; import org.bouncycastle.crypto.io.CipherOutputStream; import org.bouncycastle.util.io.Streams; import org.cryptacular.CryptoException; /** * Abstract base class for password-based encryption schemes based on salt data and iterated hashing as the basis of the * key derivation function. * *

NOTE: Classes derived from this class are not thread safe. In particular, care should be take to prevent multiple * threads from performing encryption and/or decryption concurrently.

* * @author Middleware Services * @version $Revision: 2744 $ */ public abstract class AbstractEncryptionScheme implements EncryptionScheme { /** Cipher used for encryption and decryption. */ private BufferedBlockCipher cipher; /** Cipher initialization parameters. */ private CipherParameters parameters; @Override public byte[] encrypt(final byte[] plaintext) { cipher.init(true, parameters); return process(plaintext); } @Override public void encrypt(final InputStream in, final OutputStream out) throws IOException { cipher.init(true, parameters); Streams.pipeAll(in, new CipherOutputStream(out, cipher)); } @Override public byte[] decrypt(final byte[] ciphertext) { cipher.init(false, parameters); return process(ciphertext); } @Override public void decrypt(final InputStream in, final OutputStream out) throws IOException { cipher.init(false, parameters); Streams.pipeAll(new CipherInputStream(in, cipher), out); } /** * Sets the block cipher used for encryption/decryption. * * @param bufferedBlockCipher Buffered block cipher. */ protected void setCipher(final BufferedBlockCipher bufferedBlockCipher) { if (bufferedBlockCipher == null) { throw new IllegalArgumentException("Block cipher cannot be null"); } this.cipher = bufferedBlockCipher; } /** * Sets block cipher initialization parameters. * * @param parameters Cipher-specific init params. */ protected void setCipherParameters(final CipherParameters parameters) { if (parameters == null) { throw new IllegalArgumentException("Cipher parameters cannot be null"); } this.parameters = parameters; } /** * Run the given data through the initialized underlying cipher and return the result. * * @param input Input data. * * @return Result of cipher acting on input. */ private byte[] process(final byte[] input) { final byte[] output = new byte[cipher.getOutputSize(input.length)]; int processed = cipher.processBytes(input, 0, input.length, output, 0); try { processed += cipher.doFinal(output, processed); } catch (InvalidCipherTextException e) { throw new CryptoException("Cipher error", e); } return Arrays.copyOfRange(output, 0, processed); } } cryptacular-1.2.5/src/main/java/org/cryptacular/pbe/EncryptionScheme.java000066400000000000000000000033401422604312300265110ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.pbe; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; /** * Describes a password-based encryption scheme. * * @author Middleware Services * @version $Revision: 2744 $ */ public interface EncryptionScheme { /** * Encrypts the given plaintext bytes into a byte array of ciphertext using the derived key. * * @param plaintext Input plaintext bytes. * * @return Ciphertext resulting from plaintext encryption. */ byte[] encrypt(byte[] plaintext); /** * Encrypts the data in the given plaintext input stream into ciphertext in the output stream. Use {@link * org.cryptacular.io.EncodingOutputStream} to produce ciphertext bytes that encoded as a string data in the output * stream. * * @param in Input stream of plaintext. * @param out Output stream of ciphertext. * * @throws IOException On stream read/write errors. */ void encrypt(InputStream in, OutputStream out) throws IOException; /** * Decrypts the given ciphertext into plaintext using the derived key. * * @param ciphertext Input ciphertext bytes. * * @return Plaintext resulting from ciphertext decryption. */ byte[] decrypt(byte[] ciphertext); /** * Decrypts ciphertext from an input stream into plaintext in the output stream. Use {@link * org.cryptacular.io.DecodingInputStream} to handle input ciphertext encoded as string data. * * @param in Input stream of ciphertext. * @param out Output stream of plaintext. * * @throws IOException On stream read/write errors. */ void decrypt(InputStream in, OutputStream out) throws IOException; } cryptacular-1.2.5/src/main/java/org/cryptacular/pbe/OpenSSLAlgorithm.java000066400000000000000000000046621422604312300263740ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.pbe; import org.cryptacular.spec.KeyedBlockCipherSpec; /** * Describes block ciphers allowed with the OpenSSL password-based encryption scheme. * * @author Middleware Services */ public enum OpenSSLAlgorithm { /** AES-128 in CBC mode. */ AES_128_CBC("aes-128-cbc", new KeyedBlockCipherSpec("AES", "CBC", "PKCS5", 128)), /** AES-192 in CBC mode. */ AES_192_CBC("aes-192-cbc", new KeyedBlockCipherSpec("AES", "CBC", "PKCS5", 192)), /** AES-256 in CBC mode. */ AES_256_CBC("aes-256-cbc", new KeyedBlockCipherSpec("AES", "CBC", "PKCS5", 256)), /** DES in CBC mode. */ DES_CBC("des-cbc", new KeyedBlockCipherSpec("DES", "CBC", "PKCS5", 64)), /** Triple DES in CBC mode. */ DES_EDE3_CBC("des-ede3-cbc", new KeyedBlockCipherSpec("DESede", "CBC", "PKCS5", 192)), /** 128-bit RC2 in CBC mode. */ RC2_CBC("rc2-cbc", new KeyedBlockCipherSpec("RC2", "CBC", "PKCS5", 128)), /** 40-bit RC2 in CBC mode. */ RC2_40_CBC("rc2-40-cbc", new KeyedBlockCipherSpec("RC2", "CBC", "PKCS5", 40)), /** 64-bit RC2 in CBC mode. */ RC2_64_CBC("rc2-64-cbc", new KeyedBlockCipherSpec("RC2", "CBC", "PKCS5", 64)); /** Algorithm identifier, e.g. aes-128-cbc. */ private final String algorithmId; /** Cipher algorithm specification. */ private final KeyedBlockCipherSpec cipherSpec; /** * Creates a new instance with given parameters. * * @param algId Algorithm identifier, e.g. aes-128-cbc. * @param cipherSpec Block cipher specification that corresponds to algorithm ID. */ OpenSSLAlgorithm(final String algId, final KeyedBlockCipherSpec cipherSpec) { this.algorithmId = algId; this.cipherSpec = cipherSpec; } /** @return OpenSSL algorithm identifier, e.g. aes-128-cbc. */ public String getAlgorithmId() { return algorithmId; } /** @return Cipher algorithm specification. */ public KeyedBlockCipherSpec getCipherSpec() { return cipherSpec; } /** * Converts an OID to the corresponding algorithm specification. * * @param algorithmId Algorithm OID. * * @return Algorithm spec. */ public static OpenSSLAlgorithm fromAlgorithmId(final String algorithmId) { for (OpenSSLAlgorithm alg : values()) { if (alg.getAlgorithmId().equalsIgnoreCase(algorithmId)) { return alg; } } throw new IllegalArgumentException("Unsupported algorithm " + algorithmId); } } cryptacular-1.2.5/src/main/java/org/cryptacular/pbe/OpenSSLEncryptionScheme.java000066400000000000000000000041611422604312300277170ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.pbe; import org.bouncycastle.crypto.BufferedBlockCipher; import org.bouncycastle.crypto.PBEParametersGenerator; import org.bouncycastle.crypto.generators.OpenSSLPBEParametersGenerator; import org.bouncycastle.crypto.params.ParametersWithIV; /** * Password-based encryption scheme used by OpenSSL for encrypting private keys. * * @author Middleware Services * @version $Revision: 2744 $ */ public class OpenSSLEncryptionScheme extends AbstractEncryptionScheme { /** * Creates a new instance using the given parameters. * * @param cipher Buffered block cipher algorithm. * @param salt Salt data for key generation function. * @param keyBitLength Size of derived keys in bits. * @param password Password used to derive key. */ public OpenSSLEncryptionScheme( final BufferedBlockCipher cipher, final byte[] salt, final int keyBitLength, final char[] password) { final OpenSSLPBEParametersGenerator generator = new OpenSSLPBEParametersGenerator(); generator.init(PBEParametersGenerator.PKCS5PasswordToUTF8Bytes(password), salt); setCipher(cipher); setCipherParameters(generator.generateDerivedParameters(keyBitLength)); } /** * Creates a new instance from an algorithm and salt data. * * @param algorithm OpenSSL key encryption algorithm. * @param iv Explicit IV; first 8 bytes also used for salt in PBE key generation. * @param password Password used to derive key. */ public OpenSSLEncryptionScheme(final OpenSSLAlgorithm algorithm, final byte[] iv, final char[] password) { byte[] salt = iv; if (iv.length > 8) { salt = new byte[8]; System.arraycopy(iv, 0, salt, 0, 8); } final OpenSSLPBEParametersGenerator generator = new OpenSSLPBEParametersGenerator(); generator.init(PBEParametersGenerator.PKCS5PasswordToUTF8Bytes(password), salt); setCipher(algorithm.getCipherSpec().newInstance()); setCipherParameters( new ParametersWithIV(generator.generateDerivedParameters(algorithm.getCipherSpec().getKeyLength()), iv)); } } cryptacular-1.2.5/src/main/java/org/cryptacular/pbe/PBES1Algorithm.java000066400000000000000000000060671422604312300257240ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.pbe; import org.cryptacular.spec.BufferedBlockCipherSpec; import org.cryptacular.spec.DigestSpec; /** * Password-based encryption algorithms defined in PKCS#5 for PBES1 scheme. * * @author Middleware Services * @version $Revision: 2745 $ */ public enum PBES1Algorithm { /** PBES1 encryption method with MD2 hash and DES CBC cipher. */ PbeWithMD2AndDES_CBC( "1.2.840.113549.1.5.1", new BufferedBlockCipherSpec("DES", "CBC", "PKCS5"), new DigestSpec("MD2")), /** PBES1 encryption method with MD2 hash and RC2 CBC cipher. */ PbeWithMD2AndRC2_CBC( "1.2.840.113549.1.5.4", new BufferedBlockCipherSpec("RC2", "CBC", "PKCS5"), new DigestSpec("MD2")), /** PBES1 encryption method with MD5 hash and DES CBC cipher. */ PbeWithMD5AndDES_CBC( "1.2.840.113549.1.5.3", new BufferedBlockCipherSpec("DES", "CBC", "PKCS5"), new DigestSpec("MD5")), /** PBES1 encryption method with MD5 hash and RC2 CBC cipher. */ PbeWithMD5AndRC2_CBC( "1.2.840.113549.1.5.6", new BufferedBlockCipherSpec("RC2", "CBC", "PKCS5"), new DigestSpec("MD5")), /** PBES1 encryption method with SHA1 hash and DES CBC cipher. */ PbeWithSHA1AndDES_CBC( "1.2.840.113549.1.5.10", new BufferedBlockCipherSpec("DES", "CBC", "PKCS5"), new DigestSpec("SHA1")), /** PBES1 encryption method with SHA1 hash and RC2 CBC cipher. */ PbeWithSHA1AndRC2_CBC( "1.2.840.113549.1.5.11", new BufferedBlockCipherSpec("RC2", "CBC", "PKCS5"), new DigestSpec("SHA1")); /** Algorithm identifier OID. */ private final String oid; /** Cipher algorithm specification. */ private final BufferedBlockCipherSpec cipherSpec; /** Pseudorandom function digest specification. */ private final DigestSpec digestSpec; /** * Creates a new instance with given parameters. * * @param id Algorithm OID. * @param cipherSpec Cipher algorithm specification. * @param digestSpec Digest specification used for pseudorandom function. */ PBES1Algorithm(final String id, final BufferedBlockCipherSpec cipherSpec, final DigestSpec digestSpec) { this.oid = id; this.cipherSpec = cipherSpec; this.digestSpec = digestSpec; } /** * Gets the PBE algorithm for the given object identifier. * * @param oid PBE algorithm OID. * * @return Algorithm whose identifier equals given value. * * @throws IllegalArgumentException If no matching algorithm found. */ public static PBES1Algorithm fromOid(final String oid) { for (PBES1Algorithm a : PBES1Algorithm.values()) { if (a.getOid().equals(oid)) { return a; } } throw new IllegalArgumentException("Unknown PBES1Algorithm for OID " + oid); } /** @return the oid */ public String getOid() { return oid; } /** @return Cipher algorithm specification. */ public BufferedBlockCipherSpec getCipherSpec() { return cipherSpec; } /** @return Digest algorithm. */ public DigestSpec getDigestSpec() { return digestSpec; } } cryptacular-1.2.5/src/main/java/org/cryptacular/pbe/PBES1EncryptionScheme.java000066400000000000000000000026751422604312300272560ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.pbe; import org.bouncycastle.asn1.pkcs.PBEParameter; import org.bouncycastle.crypto.PBEParametersGenerator; import org.bouncycastle.crypto.generators.PKCS5S1ParametersGenerator; /** * Implements the PBES1 encryption scheme defined in PKCS#5v2. * * @author Middleware Services * @version $Revision: 2744 $ */ public class PBES1EncryptionScheme extends AbstractEncryptionScheme { /** Number of bits in derived key. */ public static final int KEY_LENGTH = 64; /** Number of bits IV. */ public static final int IV_LENGTH = 64; /** * Creates a new instance with the given parameters. * * @param alg Describes hash/algorithm pair suitable for PBES1 scheme. * @param params Key generation function salt and iteration count. * @param password Password used to derive key. */ public PBES1EncryptionScheme(final PBES1Algorithm alg, final PBEParameter params, final char[] password) { final byte[] salt = params.getSalt(); final int iterations = params.getIterationCount().intValue(); final PKCS5S1ParametersGenerator generator = new PKCS5S1ParametersGenerator(alg.getDigestSpec().newInstance()); generator.init(PBEParametersGenerator.PKCS5PasswordToUTF8Bytes(password), salt, iterations); setCipher(alg.getCipherSpec().newInstance()); setCipherParameters(generator.generateDerivedParameters(KEY_LENGTH, IV_LENGTH)); } } cryptacular-1.2.5/src/main/java/org/cryptacular/pbe/PBES2Algorithm.java000066400000000000000000000053521422604312300257210ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.pbe; import org.cryptacular.spec.BufferedBlockCipherSpec; /** * Supported password-based encryption algorithms for PKCS#5 PBES2 encryption scheme. The ciphers mentioned in PKCS#5 * are supported as well as others in common use or of presumed value. * * @author Middleware Services * @version $Revision: 2745 $ */ public enum PBES2Algorithm { /** DES CBC cipher. */ DES("1.3.14.3.2.7", new BufferedBlockCipherSpec("DES", "CBC", "PKCS5"), 64), /** 3-DES CBC cipher. */ DESede("1.2.840.113549.3.7", new BufferedBlockCipherSpec("DESede", "CBC", "PKCS5"), 192), /** RC2 CBC cipher. */ RC2("1.2.840.113549.3.2", new BufferedBlockCipherSpec("RC2", "CBC", "PKCS5"), 64), /** RC5 CBC cipher. */ RC5("1.2.840.113549.3.9", new BufferedBlockCipherSpec("RC5", "CBC", "PKCS5"), 128), /** AES-128 CBC cipher. */ AES128("2.16.840.1.101.3.4.1.2", new BufferedBlockCipherSpec("AES", "CBC", "PKCS5"), 128), /** AES-192 CBC cipher. */ AES192("2.16.840.1.101.3.4.1.22", new BufferedBlockCipherSpec("AES", "CBC", "PKCS5"), 192), /** AES-256 CBC cipher. */ AES256("2.16.840.1.101.3.4.1.42", new BufferedBlockCipherSpec("AES", "CBC", "PKCS5"), 256); /** Algorithm identifier OID. */ private final String oid; /** Cipher algorithm specification. */ private final BufferedBlockCipherSpec cipherSpec; /** Cipher key size in bits. */ private final int keySize; /** * Creates a new instance with given parameters. * * @param id Algorithm OID. * @param cipherSpec Cipher algorithm specification. * @param keySizeBits Size of derived key in bits to be used with cipher. */ PBES2Algorithm(final String id, final BufferedBlockCipherSpec cipherSpec, final int keySizeBits) { this.oid = id; this.cipherSpec = cipherSpec; this.keySize = keySizeBits; } /** * Gets the PBE algorithm for the given object identifier. * * @param oid PBE algorithm OID. * * @return Algorithm whose identifier equals given value. * * @throws IllegalArgumentException If no matching algorithm found. */ public static PBES2Algorithm fromOid(final String oid) { for (PBES2Algorithm a : PBES2Algorithm.values()) { if (a.getOid().equals(oid)) { return a; } } throw new IllegalArgumentException("Unknown PBES1Algorithm for OID " + oid); } /** @return the oid */ public String getOid() { return oid; } /** @return Cipher algorithm specification. */ public BufferedBlockCipherSpec getCipherSpec() { return cipherSpec; } /** @return Size of derived key in bits or -1 if algorithm does not define a key size. */ public int getKeySize() { return keySize; } } cryptacular-1.2.5/src/main/java/org/cryptacular/pbe/PBES2EncryptionScheme.java000066400000000000000000000100701422604312300272430ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.pbe; import org.bouncycastle.asn1.ASN1Integer; import org.bouncycastle.asn1.ASN1OctetString; import org.bouncycastle.asn1.ASN1Sequence; import org.bouncycastle.asn1.pkcs.PBES2Parameters; import org.bouncycastle.asn1.pkcs.PBKDF2Params; import org.bouncycastle.crypto.CipherParameters; import org.bouncycastle.crypto.PBEParametersGenerator; import org.bouncycastle.crypto.engines.RC532Engine; import org.bouncycastle.crypto.generators.PKCS5S2ParametersGenerator; import org.bouncycastle.crypto.modes.CBCBlockCipher; import org.bouncycastle.crypto.paddings.PKCS7Padding; import org.bouncycastle.crypto.paddings.PaddedBufferedBlockCipher; import org.bouncycastle.crypto.params.KeyParameter; import org.bouncycastle.crypto.params.ParametersWithIV; import org.bouncycastle.crypto.params.RC2Parameters; import org.bouncycastle.crypto.params.RC5Parameters; /** * Implements the PBES2 encryption scheme defined in PKCS#5v2. * * @author Middleware Services * @version $Revision: 2744 $ */ public class PBES2EncryptionScheme extends AbstractEncryptionScheme { /** Size of derived key in bits. */ private int keyLength; /** * Creates a new instance with the given parameters. * * @param params PBES2 parameters describing the key derivation function and encryption scheme. * @param password Password used to derive key. */ public PBES2EncryptionScheme(final PBES2Parameters params, final char[] password) { final PBKDF2Params kdfParams = PBKDF2Params.getInstance(params.getKeyDerivationFunc().getParameters()); final byte[] salt = kdfParams.getSalt(); final int iterations = kdfParams.getIterationCount().intValue(); if (kdfParams.getKeyLength() != null) { keyLength = kdfParams.getKeyLength().intValue() * 8; } final PKCS5S2ParametersGenerator generator = new PKCS5S2ParametersGenerator(); generator.init(PBEParametersGenerator.PKCS5PasswordToUTF8Bytes(password), salt, iterations); initCipher(generator, params.getEncryptionScheme()); } /** * Initializes the block cipher and sets up its initialization parameters. * * @param generator Derived key generator. * @param scheme PKCS#5 encryption scheme. */ private void initCipher( final PKCS5S2ParametersGenerator generator, final org.bouncycastle.asn1.pkcs.EncryptionScheme scheme) { final PBES2Algorithm alg = PBES2Algorithm.fromOid(scheme.getAlgorithm().getId()); if (keyLength == 0) { keyLength = alg.getKeySize(); } byte[] iv = null; CipherParameters cipherParameters = generator.generateDerivedParameters(keyLength); switch (alg) { case RC2: setCipher(alg.getCipherSpec().newInstance()); final ASN1Sequence rc2Params = ASN1Sequence.getInstance(scheme.getParameters()); if (rc2Params.size() > 1) { cipherParameters = new RC2Parameters( ((KeyParameter) cipherParameters).getKey(), ASN1Integer.getInstance(rc2Params.getObjectAt(0)).getValue().intValue()); iv = ASN1OctetString.getInstance(rc2Params.getObjectAt(0)).getOctets(); } break; case RC5: final ASN1Sequence rc5Params = ASN1Sequence.getInstance(scheme.getParameters()); final int rounds = ASN1Integer.getInstance(rc5Params.getObjectAt(1)).getValue().intValue(); final int blockSize = ASN1Integer.getInstance(rc5Params.getObjectAt(2)).getValue().intValue(); if (blockSize == 32) { setCipher(new PaddedBufferedBlockCipher(new CBCBlockCipher(new RC532Engine()), new PKCS7Padding())); } cipherParameters = new RC5Parameters(((KeyParameter) cipherParameters).getKey(), rounds); if (rc5Params.size() > 3) { iv = ASN1OctetString.getInstance(rc5Params.getObjectAt(3)).getOctets(); } break; default: setCipher(alg.getCipherSpec().newInstance()); iv = ASN1OctetString.getInstance(scheme.getParameters()).getOctets(); } if (iv != null) { cipherParameters = new ParametersWithIV(cipherParameters, iv); } setCipherParameters(cipherParameters); } } cryptacular-1.2.5/src/main/java/org/cryptacular/spec/000077500000000000000000000000001422604312300225535ustar00rootroot00000000000000cryptacular-1.2.5/src/main/java/org/cryptacular/spec/AEADBlockCipherSpec.java000066400000000000000000000061371422604312300270400ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.spec; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.bouncycastle.crypto.BlockCipher; import org.bouncycastle.crypto.modes.AEADBlockCipher; import org.bouncycastle.crypto.modes.CCMBlockCipher; import org.bouncycastle.crypto.modes.EAXBlockCipher; import org.bouncycastle.crypto.modes.GCMBlockCipher; import org.bouncycastle.crypto.modes.OCBBlockCipher; /** * Describes an AEAD block cipher in terms of a (algorithm, mode) tuple and provides a facility to create a new instance * of the cipher via the {@link #newInstance()} method. * * @author Middleware Services * @version $Revision: 2744 $ */ public class AEADBlockCipherSpec implements Spec { /** String specification format, algorithm/mode. */ public static final Pattern FORMAT = Pattern.compile("(?[A-Za-z0-9_-]+)/(?\\w+)"); /** Cipher algorithm algorithm. */ private final String algorithm; /** Cipher mode, e.g. GCM, CCM. */ private final String mode; /** * Creates a new instance from a cipher algorithm and mode. * * @param algName Cipher algorithm name. * @param cipherMode Cipher mode, e.g. GCM, CCM. */ public AEADBlockCipherSpec(final String algName, final String cipherMode) { this.algorithm = algName; this.mode = cipherMode; } @Override public String getAlgorithm() { return algorithm; } /** * Gets the cipher mode. * * @return Cipher mode, e.g. CBC, OFB. */ public String getMode() { return mode; } /** * Creates a new AEAD block cipher from the specification in this instance. * * @return New AEAD block cipher instance. */ @Override public AEADBlockCipher newInstance() { final BlockCipher blockCipher = new BlockCipherSpec(algorithm).newInstance(); final AEADBlockCipher aeadBlockCipher; switch (mode) { case "GCM": aeadBlockCipher = new GCMBlockCipher(blockCipher); break; case "CCM": aeadBlockCipher = new CCMBlockCipher(blockCipher); break; case "OCB": aeadBlockCipher = new OCBBlockCipher(blockCipher, new BlockCipherSpec(algorithm).newInstance()); break; case "EAX": aeadBlockCipher = new EAXBlockCipher(blockCipher); break; default: throw new IllegalStateException("Unsupported mode " + mode); } return aeadBlockCipher; } @Override public String toString() { return algorithm + '/' + mode; } /** * Parses a string representation of a AEAD block cipher specification into an instance of this class. * * @param specification AEAD block cipher specification of the form algorithm/mode. * * @return Buffered block cipher specification instance. */ public static AEADBlockCipherSpec parse(final String specification) { final Matcher m = FORMAT.matcher(specification); if (!m.matches()) { throw new IllegalArgumentException("Invalid specification " + specification); } return new AEADBlockCipherSpec(m.group("alg"), m.group("mode")); } } cryptacular-1.2.5/src/main/java/org/cryptacular/spec/BlockCipherSpec.java000066400000000000000000000067061422604312300264270ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.spec; import org.bouncycastle.crypto.BlockCipher; import org.bouncycastle.crypto.engines.AESEngine; import org.bouncycastle.crypto.engines.BlowfishEngine; import org.bouncycastle.crypto.engines.CAST5Engine; import org.bouncycastle.crypto.engines.CAST6Engine; import org.bouncycastle.crypto.engines.CamelliaEngine; import org.bouncycastle.crypto.engines.DESEngine; import org.bouncycastle.crypto.engines.DESedeEngine; import org.bouncycastle.crypto.engines.GOST28147Engine; import org.bouncycastle.crypto.engines.NoekeonEngine; import org.bouncycastle.crypto.engines.RC2Engine; import org.bouncycastle.crypto.engines.RC564Engine; import org.bouncycastle.crypto.engines.RC6Engine; import org.bouncycastle.crypto.engines.SEEDEngine; import org.bouncycastle.crypto.engines.SerpentEngine; import org.bouncycastle.crypto.engines.SkipjackEngine; import org.bouncycastle.crypto.engines.TEAEngine; import org.bouncycastle.crypto.engines.TwofishEngine; import org.bouncycastle.crypto.engines.XTEAEngine; /** * Block cipher specification. * * @author Middleware Services */ public class BlockCipherSpec implements Spec { /** Cipher algorithm algorithm. */ private final String algorithm; /** * Creates a new instance that describes the given block cipher algorithm. * * @param algName Block cipher algorithm. */ public BlockCipherSpec(final String algName) { this.algorithm = algName; } @Override public String getAlgorithm() { return algorithm; } @Override public BlockCipher newInstance() { final BlockCipher cipher; if ("AES".equalsIgnoreCase(algorithm)) { cipher = new AESEngine(); } else if ("Blowfish".equalsIgnoreCase(algorithm)) { cipher = new BlowfishEngine(); } else if ("Camellia".equalsIgnoreCase(algorithm)) { cipher = new CamelliaEngine(); } else if ("CAST5".equalsIgnoreCase(algorithm)) { cipher = new CAST5Engine(); } else if ("CAST6".equalsIgnoreCase(algorithm)) { cipher = new CAST6Engine(); } else if ("DES".equalsIgnoreCase(algorithm)) { cipher = new DESEngine(); } else if ("DESede".equalsIgnoreCase(algorithm) || "DES3".equalsIgnoreCase(algorithm)) { cipher = new DESedeEngine(); } else if ("GOST".equalsIgnoreCase(algorithm) || "GOST28147".equals(algorithm)) { cipher = new GOST28147Engine(); } else if ("Noekeon".equalsIgnoreCase(algorithm)) { cipher = new NoekeonEngine(); } else if ("RC2".equalsIgnoreCase(algorithm)) { cipher = new RC2Engine(); } else if ("RC5".equalsIgnoreCase(algorithm)) { cipher = new RC564Engine(); } else if ("RC6".equalsIgnoreCase(algorithm)) { cipher = new RC6Engine(); } else if ("SEED".equalsIgnoreCase(algorithm)) { cipher = new SEEDEngine(); } else if ("Serpent".equalsIgnoreCase(algorithm)) { cipher = new SerpentEngine(); } else if ("Skipjack".equalsIgnoreCase(algorithm)) { cipher = new SkipjackEngine(); } else if ("TEA".equalsIgnoreCase(algorithm)) { cipher = new TEAEngine(); } else if ("Twofish".equalsIgnoreCase(algorithm)) { cipher = new TwofishEngine(); } else if ("XTEA".equalsIgnoreCase(algorithm)) { cipher = new XTEAEngine(); } else { throw new IllegalStateException("Unsupported cipher algorithm " + algorithm); } return cipher; } @Override public String toString() { return algorithm; } } cryptacular-1.2.5/src/main/java/org/cryptacular/spec/BufferedBlockCipherSpec.java000066400000000000000000000137601422604312300300700ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.spec; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.bouncycastle.crypto.BlockCipher; import org.bouncycastle.crypto.BufferedBlockCipher; import org.bouncycastle.crypto.modes.CBCBlockCipher; import org.bouncycastle.crypto.modes.CFBBlockCipher; import org.bouncycastle.crypto.modes.OFBBlockCipher; import org.bouncycastle.crypto.paddings.BlockCipherPadding; import org.bouncycastle.crypto.paddings.ISO10126d2Padding; import org.bouncycastle.crypto.paddings.ISO7816d4Padding; import org.bouncycastle.crypto.paddings.PKCS7Padding; import org.bouncycastle.crypto.paddings.PaddedBufferedBlockCipher; import org.bouncycastle.crypto.paddings.TBCPadding; import org.bouncycastle.crypto.paddings.X923Padding; import org.bouncycastle.crypto.paddings.ZeroBytePadding; /** * Describes a block cipher in terms of a (algorithm, mode, padding) tuple and provides a facility to create a new * instance of the cipher via the {@link #newInstance()} method. * * @author Middleware Services * @version $Revision: 2744 $ */ public class BufferedBlockCipherSpec implements Spec { /** String specification format, algorithm/mode/padding. */ public static final Pattern FORMAT = Pattern.compile("(?[A-Za-z0-9_-]+)/(?\\w+)/(?\\w+)"); /** Cipher algorithm algorithm. */ private final String algorithm; /** Cipher mode, e.g. CBC, OFB. */ private final String mode; /** Cipher padding scheme, e.g. PKCS5Padding. */ private final String padding; /** * Creates a new instance from an algorithm name. * * @param algName Cipher algorithm name. */ public BufferedBlockCipherSpec(final String algName) { this(algName, null, null); } /** * Creates a new instance from a cipher algorithm and mode. * * @param algName Cipher algorithm name. * @param cipherMode Cipher mode. */ public BufferedBlockCipherSpec(final String algName, final String cipherMode) { this(algName, cipherMode, null); } /** * Creates a new instance from the given cipher specifications. * * @param algName Cipher algorithm name. * @param cipherMode Cipher mode. * @param cipherPadding Cipher padding scheme algorithm. */ public BufferedBlockCipherSpec(final String algName, final String cipherMode, final String cipherPadding) { this.algorithm = algName; this.mode = cipherMode; this.padding = cipherPadding; } @Override public String getAlgorithm() { return algorithm; } /** * Gets the cipher mode. * * @return Cipher mode, e.g. CBC, OFB. */ public String getMode() { return mode; } /** * Gets the cipher padding scheme. * * @return Padding scheme algorithm, e.g. PKCS5Padding. The following names are equivalent for no padding: NULL, * Zero, None. */ public String getPadding() { return padding; } /** * Gets the simple block cipher specification corresponding to this instance. * * @return Simple block cipher specification. */ public BlockCipherSpec getBlockCipherSpec() { return new BlockCipherSpec(this.algorithm); } /** * Creates a new buffered block cipher from the specification in this instance. * * @return New buffered block cipher instance. */ @Override public BufferedBlockCipher newInstance() { BlockCipher cipher = getBlockCipherSpec().newInstance(); switch (mode) { case "CBC": cipher = new CBCBlockCipher(cipher); break; case "OFB": cipher = new OFBBlockCipher(cipher, cipher.getBlockSize()); break; case "CFB": cipher = new CFBBlockCipher(cipher, cipher.getBlockSize()); break; default: break; } if (padding != null) { return new PaddedBufferedBlockCipher(cipher, getPadding(padding)); } return new BufferedBlockCipher(cipher); } @Override public String toString() { return algorithm + '/' + mode + '/' + padding; } /** * Parses a string representation of a buffered block cipher specification into an instance of this class. * * @param specification Block cipher specification of the form algorithm/mode/padding. * * @return Buffered block cipher specification instance. */ public static BufferedBlockCipherSpec parse(final String specification) { final Matcher m = FORMAT.matcher(specification); if (!m.matches()) { throw new IllegalArgumentException("Invalid specification " + specification); } return new BufferedBlockCipherSpec(m.group("alg"), m.group("mode"), m.group("padding")); } /** * Gets a instance of block cipher padding from a padding name string. * * @param padding Name of padding algorithm. * * @return Block cipher padding instance. */ private static BlockCipherPadding getPadding(final String padding) { final String name; final int pIndex = padding.indexOf("Padding"); if (pIndex > -1) { name = padding.substring(0, pIndex); } else { name = padding; } final BlockCipherPadding blockCipherPadding; if ("ISO7816d4".equalsIgnoreCase(name) | "ISO7816".equalsIgnoreCase(name)) { blockCipherPadding = new ISO7816d4Padding(); } else if ("ISO10126".equalsIgnoreCase(name) || "ISO10126-2".equalsIgnoreCase(name)) { blockCipherPadding = new ISO10126d2Padding(); } else if ("PKCS7".equalsIgnoreCase(name) || "PKCS5".equalsIgnoreCase(name)) { blockCipherPadding = new PKCS7Padding(); } else if ("TBC".equalsIgnoreCase(name)) { blockCipherPadding = new TBCPadding(); } else if ("X923".equalsIgnoreCase(name)) { blockCipherPadding = new X923Padding(); } else if ("NULL".equalsIgnoreCase(name) || "Zero".equalsIgnoreCase(name) || "None".equalsIgnoreCase(name)) { blockCipherPadding = new ZeroBytePadding(); } else { throw new IllegalArgumentException("Invalid padding " + padding); } return blockCipherPadding; } } cryptacular-1.2.5/src/main/java/org/cryptacular/spec/CodecSpec.java000066400000000000000000000061131422604312300252470ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.spec; import org.cryptacular.codec.Base32Codec; import org.cryptacular.codec.Base64Codec; import org.cryptacular.codec.Codec; import org.cryptacular.codec.HexCodec; /** * Describes a string-to-byte encoding provides a means to create a new instance of the coed via the {@link * #newInstance()} method. * * @author Middleware Services */ public class CodecSpec implements Spec { /** Hexadecimal encoding specification. */ public static final CodecSpec HEX = new CodecSpec("Hex"); /** Lowercase hexadecimal encoding specification. */ public static final CodecSpec HEX_LOWER = new CodecSpec("Hex-Lower"); /** Uppercase hexadecimal encoding specification. */ public static final CodecSpec HEX_UPPER = new CodecSpec("Hex-Upper"); /** Base32 encoding specification. */ public static final CodecSpec BASE32 = new CodecSpec("Base32"); /** Unpadded base32 encoding specification. */ public static final CodecSpec BASE32_UNPADDED = new CodecSpec("Base32-Unpadded"); /** Base64 encoding specification. */ public static final CodecSpec BASE64 = new CodecSpec("Base64"); /** URL-safe base64 encoding specification. */ public static final CodecSpec BASE64_URLSAFE = new CodecSpec("Base64-URLSafe"); /** Unpadded base64 encoding specification. */ public static final CodecSpec BASE64_UNPADDED = new CodecSpec("Base64-Unpadded"); /** Name of encoding, e.g. "Hex, "Base64". */ private String encoding; /** * Creates a new instance of the given encoding. * * @param encoding Name of encoding. */ public CodecSpec(final String encoding) { if (encoding == null) { throw new IllegalArgumentException("Encoding cannot be null."); } this.encoding = encoding; } /** @return The name of the encoding, e.g. "Hex", "Base32", "Base64". */ @Override public String getAlgorithm() { return encoding; } @Override public Codec newInstance() { final Codec codec; if ("Hex".equalsIgnoreCase(encoding) || "Hex-Lower".equalsIgnoreCase(encoding)) { codec = new HexCodec(); } else if ("Hex-Upper".equalsIgnoreCase(encoding)) { codec = new HexCodec(true); } else if ("Base32".equalsIgnoreCase(encoding) || "Base-32".equalsIgnoreCase(encoding)) { codec = new Base32Codec(); } else if ("Base32-Unpadded".equalsIgnoreCase(encoding)) { codec = new Base32Codec("ABCDEFGHIJKLMNOPQRSTUVWXYZ234567", true); } else if ("Base64".equalsIgnoreCase(encoding) || "Base-64".equalsIgnoreCase(encoding)) { codec = new Base64Codec(); } else if ("Base64-URLSafe".equalsIgnoreCase(encoding)) { codec = new Base64Codec("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"); } else if ("Base64-Unpadded".equalsIgnoreCase(encoding)) { codec = new Base64Codec("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/", false); } else { throw new IllegalArgumentException("Invalid encoding."); } return codec; } @Override public String toString() { return encoding; } } cryptacular-1.2.5/src/main/java/org/cryptacular/spec/DigestSpec.java000066400000000000000000000112071422604312300254510ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.spec; import org.bouncycastle.crypto.Digest; import org.bouncycastle.crypto.digests.GOST3411Digest; import org.bouncycastle.crypto.digests.MD2Digest; import org.bouncycastle.crypto.digests.MD4Digest; import org.bouncycastle.crypto.digests.MD5Digest; import org.bouncycastle.crypto.digests.RIPEMD128Digest; import org.bouncycastle.crypto.digests.RIPEMD160Digest; import org.bouncycastle.crypto.digests.RIPEMD256Digest; import org.bouncycastle.crypto.digests.RIPEMD320Digest; import org.bouncycastle.crypto.digests.SHA1Digest; import org.bouncycastle.crypto.digests.SHA224Digest; import org.bouncycastle.crypto.digests.SHA256Digest; import org.bouncycastle.crypto.digests.SHA384Digest; import org.bouncycastle.crypto.digests.SHA3Digest; import org.bouncycastle.crypto.digests.SHA512Digest; import org.bouncycastle.crypto.digests.TigerDigest; import org.bouncycastle.crypto.digests.WhirlpoolDigest; /** * Describes a message digest function by name and provides a means to create a new instance of the digest via the * {@link #newInstance()} method. * * @author Middleware Services */ public class DigestSpec implements Spec { /** Digest algorithm name. */ private final String algorithm; /** Requested size of variable-size hash algorithms, e.g. SHA-3. -1 for hashes with fixed size outputs. */ private final int size; /** * Creates a new instance from the given algorithm name. * * @param algName Digest algorithm name. */ public DigestSpec(final String algName) { if (algName == null) { throw new IllegalArgumentException("Algorithm name is required."); } this.algorithm = algName; this.size = -1; } /** * Constructor for digests that have variable output size, e.g. SHA3. * * @param algName Digest algorithm name. * @param digestSize Size of resultant digest in bits. */ public DigestSpec(final String algName, final int digestSize) { if (algName == null) { throw new IllegalArgumentException("Algorithm name is required."); } this.algorithm = algName; if (digestSize < 0) { throw new IllegalArgumentException("Digest size must be positive."); } this.size = digestSize; } @Override public String getAlgorithm() { return algorithm; } /** @return Size of digest output in bytes, or -1 if the digest does not support variable size output. */ public int getSize() { return size; } /** * Creates a new digest instance. * * @return Digest instance. */ @Override public Digest newInstance() { final Digest digest; if ("GOST3411".equalsIgnoreCase(algorithm)) { digest = new GOST3411Digest(); } else if ("MD2".equalsIgnoreCase(algorithm)) { digest = new MD2Digest(); } else if ("MD4".equalsIgnoreCase(algorithm)) { digest = new MD4Digest(); } else if ("MD5".equalsIgnoreCase(algorithm)) { digest = new MD5Digest(); } else if ("RIPEMD128".equalsIgnoreCase(algorithm) || "RIPEMD-128".equalsIgnoreCase(algorithm)) { digest = new RIPEMD128Digest(); } else if ("RIPEMD160".equalsIgnoreCase(algorithm) || "RIPEMD-160".equalsIgnoreCase(algorithm)) { digest = new RIPEMD160Digest(); } else if ("RIPEMD256".equalsIgnoreCase(algorithm) || "RIPEMD-256".equalsIgnoreCase(algorithm)) { digest = new RIPEMD256Digest(); } else if ("RIPEMD320".equalsIgnoreCase(algorithm) || "RIPEMD-320".equalsIgnoreCase(algorithm)) { digest = new RIPEMD320Digest(); } else if ("SHA1".equalsIgnoreCase(algorithm) || "SHA-1".equalsIgnoreCase(algorithm)) { digest = new SHA1Digest(); } else if ("SHA224".equalsIgnoreCase(algorithm) || "SHA-224".equalsIgnoreCase(algorithm)) { digest = new SHA224Digest(); } else if ("SHA256".equalsIgnoreCase(algorithm) || "SHA-256".equalsIgnoreCase(algorithm)) { digest = new SHA256Digest(); } else if ("SHA384".equalsIgnoreCase(algorithm) || "SHA-384".equalsIgnoreCase(algorithm)) { digest = new SHA384Digest(); } else if ("SHA512".equalsIgnoreCase(algorithm) || "SHA-512".equalsIgnoreCase(algorithm)) { digest = new SHA512Digest(); } else if ("SHA3".equalsIgnoreCase(algorithm) || "SHA-3".equalsIgnoreCase(algorithm)) { digest = new SHA3Digest(size); } else if ("Tiger".equalsIgnoreCase(algorithm)) { digest = new TigerDigest(); } else if ("Whirlpool".equalsIgnoreCase(algorithm)) { digest = new WhirlpoolDigest(); } else { throw new IllegalStateException("Unsupported digest algorithm " + algorithm); } return digest; } @Override public String toString() { return algorithm; } } cryptacular-1.2.5/src/main/java/org/cryptacular/spec/KeyedBlockCipherSpec.java000066400000000000000000000021131422604312300273750ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.spec; /** * Describes a block cipher algorithm with a known key size. * * @author Middleware Services */ public class KeyedBlockCipherSpec extends BufferedBlockCipherSpec { /** Key length in bits. */ private final int keyLength; /** * Creates a new instance from the given cipher specifications. * * @param algName Cipher algorithm name. * @param cipherMode Cipher mode. * @param cipherPadding Cipher padding scheme algorithm. * @param keyBitLength Key length in bits. */ public KeyedBlockCipherSpec( final String algName, final String cipherMode, final String cipherPadding, final int keyBitLength) { super(algName, cipherMode, cipherPadding); if (keyBitLength < 0) { throw new IllegalArgumentException("Key length must be non-negative"); } this.keyLength = keyBitLength; } /** * Gets the cipher key length in bits. * * @return Key length in bits. */ public int getKeyLength() { return keyLength; } } cryptacular-1.2.5/src/main/java/org/cryptacular/spec/Spec.java000066400000000000000000000010461422604312300243110ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.spec; /** * Specification for a cryptographic primitive, e.g. block cipher, message digest, etc. * * @param Type of specification. * * @author Middleware Services */ public interface Spec { /** @return Cryptographic algorithm name. */ String getAlgorithm(); /** * Creates a new instance of the cryptographic primitive described by this specification. * * @return New instance of cryptographic primitive. */ T newInstance(); } cryptacular-1.2.5/src/main/java/org/cryptacular/spec/StreamCipherSpec.java000066400000000000000000000040471422604312300266240ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.spec; import org.bouncycastle.crypto.StreamCipher; import org.bouncycastle.crypto.engines.Grain128Engine; import org.bouncycastle.crypto.engines.HC128Engine; import org.bouncycastle.crypto.engines.HC256Engine; import org.bouncycastle.crypto.engines.ISAACEngine; import org.bouncycastle.crypto.engines.RC4Engine; import org.bouncycastle.crypto.engines.Salsa20Engine; import org.bouncycastle.crypto.engines.VMPCEngine; /** * Stream cipher specification. * * @author Middleware Services */ public class StreamCipherSpec implements Spec { /** Cipher algorithm algorithm. */ private final String algorithm; /** * Creates a new instance that describes the given stream cipher algorithm. * * @param algName Stream cipher algorithm. */ public StreamCipherSpec(final String algName) { this.algorithm = algName; } @Override public String getAlgorithm() { return algorithm; } @Override public StreamCipher newInstance() { final StreamCipher cipher; if ("Grainv1".equalsIgnoreCase(algorithm) || "Grain-v1".equalsIgnoreCase(algorithm)) { cipher = new ISAACEngine(); } else if ("Grain128".equalsIgnoreCase(algorithm) || "Grain-128".equalsIgnoreCase(algorithm)) { cipher = new Grain128Engine(); } else if ("ISAAC".equalsIgnoreCase(algorithm)) { cipher = new ISAACEngine(); } else if ("HC128".equalsIgnoreCase(algorithm)) { cipher = new HC128Engine(); } else if ("HC256".equalsIgnoreCase(algorithm)) { cipher = new HC256Engine(); } else if ("RC4".equalsIgnoreCase(algorithm)) { cipher = new RC4Engine(); } else if ("Salsa20".equalsIgnoreCase(algorithm)) { cipher = new Salsa20Engine(); } else if ("VMPC".equalsIgnoreCase(algorithm)) { cipher = new VMPCEngine(); } else { throw new IllegalStateException("Unsupported cipher algorithm " + algorithm); } return cipher; } @Override public String toString() { return algorithm; } } cryptacular-1.2.5/src/main/java/org/cryptacular/util/000077500000000000000000000000001422604312300225765ustar00rootroot00000000000000cryptacular-1.2.5/src/main/java/org/cryptacular/util/ByteUtil.java000066400000000000000000000164421422604312300252110ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.util; import java.io.IOException; import java.io.InputStream; import java.nio.ByteBuffer; import java.nio.CharBuffer; import java.nio.charset.Charset; import org.cryptacular.StreamException; /** * Utilities for working with bytes. * * @author Middleware Services */ public final class ByteUtil { /** Default character set for bytes is UTF-8. */ public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8"); /** ASCII charactr set. */ public static final Charset ASCII_CHARSET = Charset.forName("ASCII"); /** Private constructor of utilty class. */ private ByteUtil() {} /** * Converts the big-endian representation of a 32-bit integer to the equivalent integer value. * * @param data 4-byte array in big-endian format. * * @return Integer value. */ public static int toInt(final byte[] data) { return (data[0] << 24) | ((data[1] & 0xff) << 16) | ((data[2] & 0xff) << 8) | (data[3] & 0xff); } /** * Converts an unsigned byte into an integer. * * @param unsigned Unsigned byte. * * @return Integer value. */ public static int toInt(final byte unsigned) { return 0x000000FF & unsigned; } /** * Reads 4-bytes from the input stream and converts to a 32-bit integer. * * @param in Stream from which to read 4 bytes. * * @return Integer value. * * @throws StreamException on stream IO errors. */ public static int readInt(final InputStream in) throws StreamException { try { return (in.read() << 24) | ((in.read() & 0xff) << 16) | ((in.read() & 0xff) << 8) | (in.read() & 0xff); } catch (IOException e) { throw new StreamException(e); } } /** * Converts the big-endian representation of a 64-bit integer to the equivalent long value. * * @param data 8-byte array in big-endian format. * * @return Long integer value. */ public static long toLong(final byte[] data) { return ((long) data[0] << 56) | (((long) data[1] & 0xff) << 48) | (((long) data[2] & 0xff) << 40) | (((long) data[3] & 0xff) << 32) | (((long) data[4] & 0xff) << 24) | (((long) data[5] & 0xff) << 16) | (((long) data[6] & 0xff) << 8) | ((long) data[7] & 0xff); } /** * Reads 8-bytes from the input stream and converts to a 64-bit long integer. * * @param in Stream from which to read 8 bytes. * * @return Long integer value. * * @throws StreamException on stream IO errors. */ public static long readLong(final InputStream in) throws StreamException { try { return ((long) in.read() << 56) | (((long) in.read() & 0xff) << 48) | (((long) in.read() & 0xff) << 40) | (((long) in.read() & 0xff) << 32) | (((long) in.read() & 0xff) << 24) | (((long) in.read() & 0xff) << 16) | (((long) in.read() & 0xff) << 8) | ((long) in.read() & 0xff); } catch (IOException e) { throw new StreamException(e); } } /** * Converts an integer into a 4-byte big endian array. * * @param value Integer value to convert. * * @return 4-byte big-endian representation of integer value. */ public static byte[] toBytes(final int value) { final byte[] bytes = new byte[4]; toBytes(value, bytes, 0); return bytes; } /** * Converts an integer into a 4-byte big endian array. * * @param value Integer value to convert. * @param output Array into which bytes are placed. * @param offset Offset into output array at which output bytes start. */ public static void toBytes(final int value, final byte[] output, final int offset) { int shift = 24; for (int i = 0; i < 4; i++) { output[offset + i] = (byte) (value >> shift); shift -= 8; } } /** * Converts a long integer into an 8-byte big endian array. * * @param value Long integer value to convert. * * @return 8-byte big-endian representation of long integer value. */ public static byte[] toBytes(final long value) { final byte[] bytes = new byte[8]; toBytes(value, bytes, 0); return bytes; } /** * Converts an integer into a 8-byte big endian array. * * @param value Long value to convert. * @param output Array into which bytes are placed. * @param offset Offset into output array at which output bytes start. */ public static void toBytes(final long value, final byte[] output, final int offset) { int shift = 56; for (int i = 0; i < 8; i++) { output[offset + i] = (byte) (value >> shift); shift -= 8; } } /** * Converts a byte array into a string in the UTF-8 character set. * * @param bytes Byte array to convert. * * @return UTF-8 string representation of bytes. */ public static String toString(final byte[] bytes) { return new String(bytes, DEFAULT_CHARSET); } /** * Converts a portion of a byte array into a string in the UTF-8 character set. * * @param bytes Byte array to convert. * @param offset Offset into byte array where string content begins. * @param length Total number of bytes to convert. * * @return UTF-8 string representation of bytes. */ public static String toString(final byte[] bytes, final int offset, final int length) { return new String(bytes, offset, length, DEFAULT_CHARSET); } /** * Converts a byte buffer into a string in the UTF-8 character set. * * @param buffer Byte buffer to convert. * * @return UTF-8 string representation of bytes. */ public static String toString(final ByteBuffer buffer) { return toCharBuffer(buffer).toString(); } /** * Converts a byte buffer into a character buffer. * * @param buffer Byte buffer to convert. * * @return Character buffer containing UTF-8 string representation of bytes. */ public static CharBuffer toCharBuffer(final ByteBuffer buffer) { return DEFAULT_CHARSET.decode(buffer); } /** * Converts a string into bytes in the UTF-8 character set. * * @param s String to convert. * * @return Byte buffer containing byte representation of string. */ public static ByteBuffer toByteBuffer(final String s) { return DEFAULT_CHARSET.encode(CharBuffer.wrap(s)); } /** * Converts a string into bytes in the UTF-8 character set. * * @param s String to convert. * * @return Byte array containing byte representation of string. */ public static byte[] toBytes(final String s) { return s.getBytes(DEFAULT_CHARSET); } /** * Converts an integer into an unsigned byte. All bits above 1 byte are truncated. * * @param b Integer value. * * @return Unsigned byte as a byte. */ public static byte toUnsignedByte(final int b) { return (byte) (0x000000FF & b); } /** * Converts a byte buffer into a byte array. * * @param buffer Byte buffer to convert. * * @return Byte array corresponding to bytes of buffer from current position to limit. */ public static byte[] toArray(final ByteBuffer buffer) { final int size = buffer.limit() - buffer.position(); if (buffer.hasArray() && size == buffer.capacity()) { return buffer.array(); } final byte[] array = new byte[size]; buffer.get(array); return array; } } cryptacular-1.2.5/src/main/java/org/cryptacular/util/CertUtil.java000066400000000000000000000351001422604312300251730ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.util; import java.io.ByteArrayInputStream; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.security.PrivateKey; import java.security.cert.Certificate; import java.security.cert.CertificateException; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.List; import org.bouncycastle.asn1.x509.GeneralName; import org.bouncycastle.asn1.x509.GeneralNames; import org.bouncycastle.asn1.x509.GeneralNamesBuilder; import org.bouncycastle.asn1.x509.KeyPurposeId; import org.bouncycastle.asn1.x509.KeyUsage; import org.bouncycastle.asn1.x509.PolicyInformation; import org.cryptacular.EncodingException; import org.cryptacular.StreamException; import org.cryptacular.x509.ExtensionReader; import org.cryptacular.x509.GeneralNameType; import org.cryptacular.x509.KeyUsageBits; import org.cryptacular.x509.dn.NameReader; import org.cryptacular.x509.dn.StandardAttributeType; /** * Utility class providing convenience methods for common operations on X.509 certificates. * * @author Middleware Services */ public final class CertUtil { /** Private constructor of utility class. */ private CertUtil() {} /** * Gets the common name attribute (CN) of the certificate subject distinguished name. * * @param cert Certificate to examine. * * @return Subject CN or null if no CN attribute is defined in the subject DN. * * @throws EncodingException on cert field extraction. */ public static String subjectCN(final X509Certificate cert) throws EncodingException { return new NameReader(cert).readSubject().getValue(StandardAttributeType.CommonName); } /** * Gets all subject alternative names defined on the given certificate. * * @param cert X.509 certificate to examine. * * @return List of subject alternative names or null if no subject alt names are defined. * * @throws EncodingException on cert field extraction. */ public static GeneralNames subjectAltNames(final X509Certificate cert) throws EncodingException { return new ExtensionReader(cert).readSubjectAlternativeName(); } /** * Gets all subject alternative names of the given type(s) on the given cert. * * @param cert X.509 certificate to examine. * @param types One or more subject alternative name types to fetch. * * @return List of subject alternative names of the matching type(s) or null if none found. * * @throws EncodingException on cert field extraction. */ public static GeneralNames subjectAltNames(final X509Certificate cert, final GeneralNameType... types) throws EncodingException { final GeneralNamesBuilder builder = new GeneralNamesBuilder(); final GeneralNames altNames = subjectAltNames(cert); if (altNames != null) { for (GeneralName name : altNames.getNames()) { for (GeneralNameType type : types) { if (type.ordinal() == name.getTagNo()) { builder.addName(name); } } } } final GeneralNames names = builder.build(); if (names.getNames().length == 0) { return null; } return names; } /** * Gets a list of all subject names defined for the given certificate. The list includes the first common name (CN) * specified in the subject distinguished name (if defined) and all subject alternative names. * * @param cert X.509 certificate to examine. * * @return List of subject names. * * @throws EncodingException on cert field extraction. */ public static List subjectNames(final X509Certificate cert) throws EncodingException { final List names = new ArrayList<>(); final String cn = subjectCN(cert); if (cn != null) { names.add(cn); } final GeneralNames altNames = subjectAltNames(cert); if (altNames == null) { return names; } for (GeneralName name : altNames.getNames()) { names.add(name.getName().toString()); } return names; } /** * Gets a list of subject names defined for the given certificate. The list includes the first common name (CN) * specified in the subject distinguished name (if defined) and all subject alternative names of the given type. * * @param cert X.509 certificate to examine. * @param types One or more subject alternative name types to fetch. * * @return List of subject names. * * @throws EncodingException on cert field extraction. */ public static List subjectNames(final X509Certificate cert, final GeneralNameType... types) throws EncodingException { final List names = new ArrayList<>(); final String cn = subjectCN(cert); if (cn != null) { names.add(cn); } final GeneralNames altNames = subjectAltNames(cert, types); if (altNames == null) { return names; } for (GeneralName name : altNames.getNames()) { names.add(name.getName().toString()); } return names; } /** * Finds a certificate whose public key is paired with the given private key. * * @param key Private key used to find matching public key. * @param candidates Array of candidate certificates. * * @return Certificate whose public key forms a keypair with the private key or null if no match is found. * * @throws EncodingException on cert field extraction. */ public static X509Certificate findEntityCertificate(final PrivateKey key, final X509Certificate... candidates) throws EncodingException { return findEntityCertificate(key, Arrays.asList(candidates)); } /** * Finds a certificate whose public key is paired with the given private key. * * @param key Private key used to find matching public key. * @param candidates Collection of candidate certificates. * * @return Certificate whose public key forms a keypair with the private key or null if no match is found. * * @throws EncodingException on cert field extraction. */ public static X509Certificate findEntityCertificate( final PrivateKey key, final Collection candidates) throws EncodingException { for (X509Certificate candidate : candidates) { if (KeyPairUtil.isKeyPair(candidate.getPublicKey(), key)) { return candidate; } } return null; } /** * Reads an X.509 certificate from ASN.1 encoded format in the file at the given location. * * @param path Path to file containing an DER or PEM encoded X.509 certificate. * * @return Certificate. * * @throws EncodingException on cert parsing errors. * @throws StreamException on IO errors. */ public static X509Certificate readCertificate(final String path) throws EncodingException, StreamException { return readCertificate(StreamUtil.makeStream(new File(path))); } /** * Reads an X.509 certificate from ASN.1 encoded format from the given file. * * @param file File containing an DER or PEM encoded X.509 certificate. * * @return Certificate. * * @throws EncodingException on cert parsing errors. * @throws StreamException on IO errors. */ public static X509Certificate readCertificate(final File file) throws EncodingException, StreamException { return readCertificate(StreamUtil.makeStream(file)); } /** * Reads an X.509 certificate from ASN.1 encoded data in the given stream. * * @param in Input stream containing PEM or DER encoded X.509 certificate. * * @return Certificate. * * @throws EncodingException on cert parsing errors. * @throws StreamException on IO errors. */ public static X509Certificate readCertificate(final InputStream in) throws EncodingException, StreamException { try { final CertificateFactory factory = CertificateFactory.getInstance("X.509"); return (X509Certificate) factory.generateCertificate(in); } catch (CertificateException e) { if (e.getCause() instanceof IOException) { throw new StreamException((IOException) e.getCause()); } throw new EncodingException("Cannot decode certificate", e); } } /** * Creates an X.509 certificate from its ASN.1 encoded form. * * @param encoded PEM or DER encoded ASN.1 data. * * @return Certificate. * * @throws EncodingException on cert parsing errors. */ public static X509Certificate decodeCertificate(final byte[] encoded) throws EncodingException { return readCertificate(new ByteArrayInputStream(encoded)); } /** * Reads an X.509 certificate chain from ASN.1 encoded format in the file at the given location. * * @param path Path to file containing a sequence of PEM or DER encoded certificates or PKCS#7 certificate chain. * * @return Certificate. * * @throws EncodingException on cert parsing errors. * @throws StreamException on IO errors. */ public static X509Certificate[] readCertificateChain(final String path) throws EncodingException, StreamException { return readCertificateChain(StreamUtil.makeStream(new File(path))); } /** * Reads an X.509 certificate chain from ASN.1 encoded format from the given file. * * @param file File containing a sequence of PEM or DER encoded certificates or PKCS#7 certificate chain. * * @return Certificate. * * @throws EncodingException on cert parsing errors. * @throws StreamException on IO errors. */ public static X509Certificate[] readCertificateChain(final File file) throws EncodingException, StreamException { return readCertificateChain(StreamUtil.makeStream(file)); } /** * Reads an X.509 certificate chain from ASN.1 encoded data in the given stream. * * @param in Input stream containing a sequence of PEM or DER encoded certificates or PKCS#7 certificate chain. * * @return Certificate. * * @throws EncodingException on cert parsing errors. * @throws StreamException on IO errors. */ public static X509Certificate[] readCertificateChain(final InputStream in) throws EncodingException, StreamException { try { final CertificateFactory factory = CertificateFactory.getInstance("X.509"); final Collection certs = factory.generateCertificates(in); return certs.toArray(new X509Certificate[certs.size()]); } catch (CertificateException e) { if (e.getCause() instanceof IOException) { throw new StreamException((IOException) e.getCause()); } throw new EncodingException("Cannot decode certificate", e); } } /** * Creates an X.509 certificate chain from its ASN.1 encoded form. * * @param encoded Sequence of PEM or DER encoded certificates or PKCS#7 certificate chain. * * @return Certificate. * * @throws EncodingException on cert parsing errors. */ public static X509Certificate[] decodeCertificateChain(final byte[] encoded) throws EncodingException { return readCertificateChain(new ByteArrayInputStream(encoded)); } /** * Determines whether the certificate allows the given basic key usages. * * @param cert Certificate to check. * @param bits One or more basic key usage types to check. * * @return True if certificate allows all given usage types, false otherwise. * * @throws EncodingException on cert field extraction. */ public static boolean allowsUsage(final X509Certificate cert, final KeyUsageBits... bits) throws EncodingException { final KeyUsage usage = new ExtensionReader(cert).readKeyUsage(); for (KeyUsageBits bit : bits) { if (!bit.isSet(usage)) { return false; } } return true; } /** * Determines whether the certificate allows the given extended key usages. * * @param cert Certificate to check. * @param purposes One ore more extended key usage purposes to check. * * @return True if certificate allows all given purposes, false otherwise. * * @throws EncodingException on cert field extraction. */ public static boolean allowsUsage(final X509Certificate cert, final KeyPurposeId... purposes) throws EncodingException { final List allowedUses = new ExtensionReader(cert).readExtendedKeyUsage(); for (KeyPurposeId purpose : purposes) { if (allowedUses == null || !allowedUses.contains(purpose)) { return false; } } return true; } /** * Determines whether the certificate defines all of the given certificate policies. * * @param cert Certificate to check. * @param policyOidsToCheck One or more certificate policy OIDs to check. * * @return True if certificate defines all given policy OIDs, false otherwise. * * @throws EncodingException on cert field extraction. */ public static boolean hasPolicies(final X509Certificate cert, final String... policyOidsToCheck) throws EncodingException { final List policies = new ExtensionReader(cert).readCertificatePolicies(); boolean hasPolicy; for (String policyOid : policyOidsToCheck) { hasPolicy = false; if (policies != null) { for (PolicyInformation policy : policies) { if (policy.getPolicyIdentifier().getId().equals(policyOid)) { hasPolicy = true; break; } } } if (!hasPolicy) { return false; } } return true; } /** * Gets the subject key identifier of the given certificate in delimited hexadecimal format, e.g. * 25:48:2f:28:ec:5d:19:bb:1d:25:ae:94:93:b1:7b:b5:35:96:24:66. * * @param cert Certificate to process. * * @return Subject key identifier in colon-delimited hex format. * * @throws EncodingException on cert field extraction. */ public static String subjectKeyId(final X509Certificate cert) throws EncodingException { return CodecUtil.hex(new ExtensionReader(cert).readSubjectKeyIdentifier().getKeyIdentifier(), true); } /** * Gets the authority key identifier of the given certificate in delimited hexadecimal format, e.g. * 25:48:2f:28:ec:5d:19:bb:1d:25:ae:94:93:b1:7b:b5:35:96:24:66. * * @param cert Certificate to process. * * @return Authority key identifier in colon-delimited hex format. * * @throws EncodingException on cert field extraction. */ public static String authorityKeyId(final X509Certificate cert) throws EncodingException { return CodecUtil.hex(new ExtensionReader(cert).readAuthorityKeyIdentifier().getKeyIdentifier(), true); } } cryptacular-1.2.5/src/main/java/org/cryptacular/util/CipherUtil.java000066400000000000000000000352331422604312300255170ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.util; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.function.Function; import javax.crypto.SecretKey; import org.bouncycastle.crypto.BlockCipher; import org.bouncycastle.crypto.modes.AEADBlockCipher; import org.bouncycastle.crypto.paddings.PKCS7Padding; import org.bouncycastle.crypto.paddings.PaddedBufferedBlockCipher; import org.bouncycastle.crypto.params.AEADParameters; import org.bouncycastle.crypto.params.KeyParameter; import org.bouncycastle.crypto.params.ParametersWithIV; import org.cryptacular.CiphertextHeader; import org.cryptacular.CiphertextHeaderV2; import org.cryptacular.CryptoException; import org.cryptacular.EncodingException; import org.cryptacular.StreamException; import org.cryptacular.adapter.AEADBlockCipherAdapter; import org.cryptacular.adapter.BlockCipherAdapter; import org.cryptacular.adapter.BufferedBlockCipherAdapter; import org.cryptacular.generator.Nonce; /** * Utility class that performs encryption and decryption operations using a block cipher. * * @author Middleware Services */ public final class CipherUtil { /** Mac size in bits. */ private static final int MAC_SIZE_BITS = 128; /** Private constructor of utility class. */ private CipherUtil() {} /** * Encrypts data using an AEAD cipher. A {@link CiphertextHeaderV2} is prepended to the resulting ciphertext and * used as AAD (Additional Authenticated Data) passed to the AEAD cipher. * * @param cipher AEAD cipher. * @param key Encryption key. * @param nonce Nonce generator. * @param data Plaintext data to be encrypted. * * @return Concatenation of encoded {@link CiphertextHeaderV2} and encrypted data that completely fills the returned * byte array. * * @throws CryptoException on encryption errors. */ public static byte[] encrypt(final AEADBlockCipher cipher, final SecretKey key, final Nonce nonce, final byte[] data) throws CryptoException { final byte[] iv = nonce.generate(); final byte[] header = new CiphertextHeaderV2(iv, "1").encode(key); cipher.init(true, new AEADParameters(new KeyParameter(key.getEncoded()), MAC_SIZE_BITS, iv, header)); return encrypt(new AEADBlockCipherAdapter(cipher), header, data); } /** * Encrypts data using an AEAD cipher. A {@link CiphertextHeaderV2} is prepended to the resulting ciphertext and used * as AAD (Additional Authenticated Data) passed to the AEAD cipher. * * @param cipher AEAD cipher. * @param key Encryption key. * @param nonce Nonce generator. * @param input Input stream containing plaintext data. * @param output Output stream that receives a {@link CiphertextHeaderV2} followed by ciphertext data produced by * the AEAD cipher in encryption mode. * * @throws CryptoException on encryption errors. * @throws StreamException on IO errors. */ public static void encrypt( final AEADBlockCipher cipher, final SecretKey key, final Nonce nonce, final InputStream input, final OutputStream output) throws CryptoException, StreamException { final byte[] iv = nonce.generate(); final byte[] header = new CiphertextHeaderV2(iv, "1").encode(key); cipher.init(true, new AEADParameters(new KeyParameter(key.getEncoded()), MAC_SIZE_BITS, iv, header)); writeHeader(header, output); process(new AEADBlockCipherAdapter(cipher), input, output); } /** * Decrypts data using an AEAD cipher. * * @param cipher AEAD cipher. * @param key Encryption key. * @param data Ciphertext data containing a prepended {@link CiphertextHeaderV2}. The header is treated as AAD input * to the cipher that is verified during decryption. * * @return Decrypted data that completely fills the returned byte array. * * @throws CryptoException on encryption errors. * @throws EncodingException on decoding cyphertext header. */ public static byte[] decrypt(final AEADBlockCipher cipher, final SecretKey key, final byte[] data) throws CryptoException, EncodingException { final CiphertextHeader header = decodeHeader(data, String -> key); final byte[] nonce = header.getNonce(); final byte[] hbytes = header.encode(); cipher.init(false, new AEADParameters(new KeyParameter(key.getEncoded()), MAC_SIZE_BITS, nonce, hbytes)); return decrypt(new AEADBlockCipherAdapter(cipher), data, header.getLength()); } /** * Decrypts data using an AEAD cipher. * * @param cipher AEAD cipher. * @param key Encryption key. * @param input Input stream containing a {@link CiphertextHeaderV2} followed by ciphertext data. The header is * treated as AAD input to the cipher that is verified during decryption. * @param output Output stream that receives plaintext produced by block cipher in decryption mode. * * @throws CryptoException on encryption errors. * @throws EncodingException on decoding cyphertext header. * @throws StreamException on IO errors. */ public static void decrypt( final AEADBlockCipher cipher, final SecretKey key, final InputStream input, final OutputStream output) throws CryptoException, EncodingException, StreamException { final CiphertextHeader header = decodeHeader(input, String -> key); final byte[] nonce = header.getNonce(); final byte[] hbytes = header.encode(); cipher.init(false, new AEADParameters(new KeyParameter(key.getEncoded()), MAC_SIZE_BITS, nonce, hbytes)); process(new AEADBlockCipherAdapter(cipher), input, output); } /** * Encrypts data using the given block cipher with PKCS5 padding. A {@link CiphertextHeaderV2} is prepended to the * resulting ciphertext. * * @param cipher Block cipher. * @param key Encryption key. * @param nonce IV generator. Callers must take care to ensure that the length of generated IVs is equal to the * cipher block size. * @param data Plaintext data to be encrypted. * * @return Concatenation of encoded {@link CiphertextHeaderV2} and encrypted data that completely fills the returned * byte array. * * @throws CryptoException on encryption errors. */ public static byte[] encrypt(final BlockCipher cipher, final SecretKey key, final Nonce nonce, final byte[] data) throws CryptoException { final byte[] iv = nonce.generate(); final byte[] header = new CiphertextHeaderV2(iv, "1").encode(key); final PaddedBufferedBlockCipher padded = new PaddedBufferedBlockCipher(cipher, new PKCS7Padding()); padded.init(true, new ParametersWithIV(new KeyParameter(key.getEncoded()), iv)); return encrypt(new BufferedBlockCipherAdapter(padded), header, data); } /** * Encrypts data using the given block cipher with PKCS5 padding. A {@link CiphertextHeader} is prepended to the * resulting ciphertext. * * @param cipher Block cipher. * @param key Encryption key. * @param nonce IV generator. Callers must take care to ensure that the length of generated IVs is equal to the * cipher block size. * @param input Input stream containing plaintext data. * @param output Output stream that receives ciphertext produced by block cipher in encryption mode. * * @throws CryptoException on encryption errors. * @throws StreamException on IO errors. */ public static void encrypt( final BlockCipher cipher, final SecretKey key, final Nonce nonce, final InputStream input, final OutputStream output) throws CryptoException, StreamException { final byte[] iv = nonce.generate(); final byte[] header = new CiphertextHeaderV2(iv, "1").encode(key); final PaddedBufferedBlockCipher padded = new PaddedBufferedBlockCipher(cipher, new PKCS7Padding()); padded.init(true, new ParametersWithIV(new KeyParameter(key.getEncoded()), iv)); writeHeader(header, output); process(new BufferedBlockCipherAdapter(padded), input, output); } /** * Decrypts data using the given block cipher with PKCS5 padding. * * @param cipher Block cipher. * @param key Encryption key. * @param data Ciphertext data containing a prepended {@link CiphertextHeader}. * * @return Decrypted data that completely fills the returned byte array. * * @throws CryptoException on encryption errors. * @throws EncodingException on decoding cyphertext header. */ public static byte[] decrypt(final BlockCipher cipher, final SecretKey key, final byte[] data) throws CryptoException, EncodingException { final CiphertextHeader header = decodeHeader(data, String -> key); final PaddedBufferedBlockCipher padded = new PaddedBufferedBlockCipher(cipher, new PKCS7Padding()); padded.init(false, new ParametersWithIV(new KeyParameter(key.getEncoded()), header.getNonce())); return decrypt(new BufferedBlockCipherAdapter(padded), data, header.getLength()); } /** * Decrypts data using the given block cipher with PKCS5 padding. * * @param cipher Block cipher. * @param key Encryption key. * @param input Input stream containing a {@link CiphertextHeader} followed by ciphertext data. * @param output Output stream that receives plaintext produced by block cipher in decryption mode. * * @throws CryptoException on encryption errors. * @throws EncodingException on decoding cyphertext header. * @throws StreamException on IO errors. */ public static void decrypt( final BlockCipher cipher, final SecretKey key, final InputStream input, final OutputStream output) throws CryptoException, EncodingException, StreamException { final CiphertextHeader header = decodeHeader(input, String -> key); final PaddedBufferedBlockCipher padded = new PaddedBufferedBlockCipher(cipher, new PKCS7Padding()); padded.init(false, new ParametersWithIV(new KeyParameter(key.getEncoded()), header.getNonce())); process(new BufferedBlockCipherAdapter(padded), input, output); } /** * Decodes the ciphertext header at the start of the given byte array. * Supports both original (deprecated) and v2 formats. * * @param data Ciphertext data with prepended header. * @param keyLookup Decryption key lookup function. * * @return Ciphertext header instance. */ public static CiphertextHeader decodeHeader(final byte[] data, final Function keyLookup) { try { return CiphertextHeaderV2.decode(data, keyLookup); } catch (EncodingException e) { return CiphertextHeader.decode(data); } } /** * Decodes the ciphertext header at the start of the given input stream. * Supports both original (deprecated) and v2 formats. * * @param in Ciphertext stream that is positioned at the start of the ciphertext header. * @param keyLookup Decryption key lookup function. * * @return Ciphertext header instance. */ public static CiphertextHeader decodeHeader(final InputStream in, final Function keyLookup) { CiphertextHeader header; try { // Mark the stream start position so we can try again with old format header if (in.markSupported()) { in.mark(4); } header = CiphertextHeaderV2.decode(in, keyLookup); } catch (EncodingException e) { try { in.reset(); } catch (IOException ioe) { throw new StreamException("Stream error trying to process old header format: " + ioe.getMessage()); } header = CiphertextHeader.decode(in); } return header; } /** * Encrypts the given data. * * @param cipher Adapter for either a block or AEAD cipher. * @param header Encoded ciphertext header. * @param data Plaintext data to encrypt. * * @return Concatenation of encoded header and encrypted data that completely fills the returned byte array. */ private static byte[] encrypt(final BlockCipherAdapter cipher, final byte[] header, final byte[] data) { final int outSize = header.length + cipher.getOutputSize(data.length); final byte[] output = new byte[outSize]; System.arraycopy(header, 0, output, 0, header.length); int outOff = header.length; outOff += cipher.processBytes(data, 0, data.length, output, outOff); cipher.doFinal(output, outOff); cipher.reset(); return output; } /** * Decrypts the given data. * * @param cipher Adapter for either a block or AEAD cipher. * @param data Ciphertext data containing prepended header bytes. * @param inOff Offset into ciphertext at which encrypted data starts (i.e. after header). * * @return Decrypted data that completely fills the returned byte array. */ private static byte[] decrypt(final BlockCipherAdapter cipher, final byte[] data, final int inOff) { final int len = data.length - inOff; final int outSize = cipher.getOutputSize(len); final byte[] output = new byte[outSize]; int outOff = cipher.processBytes(data, inOff, len, output, 0); outOff += cipher.doFinal(output, outOff); cipher.reset(); if (outOff < output.length) { final byte[] temp = new byte[outOff]; System.arraycopy(output, 0, temp, 0, outOff); return temp; } return output; } /** * Performs encryption or decryption on the given input stream based on the underlying cipher mode and writes the * result to the given output stream. * * @param cipher Adapter for either a block or AEAD cipher. * @param input Input stream containing data to be processed by the cipher. * @param output Output stream that receives the output of the cipher acting on the input. */ private static void process(final BlockCipherAdapter cipher, final InputStream input, final OutputStream output) { final int inSize = 1024; final int outSize = cipher.getOutputSize(inSize); final byte[] inBuf = new byte[inSize]; final byte[] outBuf = new byte[outSize > inSize ? outSize : inSize]; int readLen; int writeLen; try { while ((readLen = input.read(inBuf)) > 0) { writeLen = cipher.processBytes(inBuf, 0, readLen, outBuf, 0); output.write(outBuf, 0, writeLen); } writeLen = cipher.doFinal(outBuf, 0); output.write(outBuf, 0, writeLen); } catch (IOException e) { throw new StreamException(e); } } /** * Writes a ciphertext header to the output stream. * * @param header Ciphertext header bytes. * @param output Output stream. */ private static void writeHeader(final byte[] header, final OutputStream output) { try { output.write(header, 0, header.length); } catch (IOException e) { throw new StreamException(e); } } } cryptacular-1.2.5/src/main/java/org/cryptacular/util/CodecUtil.java000066400000000000000000000125371422604312300253240ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.util; import java.nio.ByteBuffer; import java.nio.CharBuffer; import org.cryptacular.EncodingException; import org.cryptacular.codec.Base32Decoder; import org.cryptacular.codec.Base32Encoder; import org.cryptacular.codec.Base64Decoder; import org.cryptacular.codec.Base64Encoder; import org.cryptacular.codec.Decoder; import org.cryptacular.codec.Encoder; import org.cryptacular.codec.HexDecoder; import org.cryptacular.codec.HexEncoder; /** * Utility class for common encoding conversions. * * @author Middleware Services */ public final class CodecUtil { /** Private constructor of utility class. */ private CodecUtil() {} /** * Encodes raw bytes to the equivalent hexadecimal encoded string. * * @param raw Raw bytes to encode. * * @return Hexadecimal encoded string. * * @throws EncodingException on encoding errors. */ public static String hex(final byte[] raw) throws EncodingException { return encode(new HexEncoder(), raw); } /** * Encodes raw bytes to the equivalent hexadecimal encoded string with optional delimiting of output. * * @param raw Raw bytes to encode. * @param delimit True to delimit every two characters (i.e. every byte) of output with ':' character, false * otherwise. * * @return Hexadecimal encoded string. * * @throws EncodingException on encoding errors. */ public static String hex(final byte[] raw, final boolean delimit) throws EncodingException { return encode(new HexEncoder(delimit), raw); } /** * Decodes a hexadecimal encoded string to raw bytes. * * @param encoded Hex encoded character data. * * @return Raw bytes of hex string. * * @throws EncodingException on decoding errors. */ public static byte[] hex(final CharSequence encoded) throws EncodingException { return decode(new HexDecoder(), encoded); } /** * Encodes bytes into base 64-encoded string. * * @param raw Raw bytes to encode. * * @return Base64-encoded string. * * @throws EncodingException on encoding errors. */ public static String b64(final byte[] raw) throws EncodingException { return encode(new Base64Encoder(), raw); } /** * Decodes a base64-encoded string into raw bytes. * * @param encoded Base64-encoded character data. * * @return Base64-decoded bytes. * * @throws EncodingException on decoding errors. */ public static byte[] b64(final CharSequence encoded) throws EncodingException { return decode(new Base64Decoder(), encoded); } /** * Encodes bytes into base64-encoded string. * * @param raw Raw bytes to encode. * @param lineLength Length of each base64-encoded line in output. * * @return Base64-encoded string. * * @throws EncodingException on encoding errors. */ public static String b64(final byte[] raw, final int lineLength) throws EncodingException { return encode(new Base64Encoder(lineLength), raw); } /** * Encodes bytes into base 32-encoded string. * * @param raw Raw bytes to encode. * * @return Base32-encoded string. * * @throws EncodingException on encoding errors. */ public static String b32(final byte[] raw) throws EncodingException { return encode(new Base32Encoder(), raw); } /** * Decodes a base32-encoded string into raw bytes. * * @param encoded Base32-encoded character data. * * @return Base64-decoded bytes. * * @throws EncodingException on decoding errors. */ public static byte[] b32(final CharSequence encoded) throws EncodingException { return decode(new Base32Decoder(), encoded); } /** * Encodes bytes into base32-encoded string. * * @param raw Raw bytes to encode. * @param lineLength Length of each base32-encoded line in output. * * @return Base32-encoded string. * * @throws EncodingException on encoding errors. */ public static String b32(final byte[] raw, final int lineLength) throws EncodingException { return encode(new Base32Encoder(lineLength), raw); } /** * Encodes raw bytes using the given encoder. * * @param encoder Encoder to perform byte-to-char conversion. * @param raw Raw bytes to encode. * * @return Encoded data as a string. * * @throws EncodingException on encoding errors. */ public static String encode(final Encoder encoder, final byte[] raw) throws EncodingException { final CharBuffer output = CharBuffer.allocate(encoder.outputSize(raw.length)); encoder.encode(ByteBuffer.wrap(raw), output); encoder.finalize(output); return output.flip().toString(); } /** * Decodes the given encoded data using the given char-to-byte decoder. * * @param decoder Decoder to perform char-to-byte conversion. * @param encoded Encoded character data. * * @return Decoded data as raw bytes. * * @throws EncodingException on decoding errors. */ public static byte[] decode(final Decoder decoder, final CharSequence encoded) throws EncodingException { final ByteBuffer output = ByteBuffer.allocate(decoder.outputSize(encoded.length())); decoder.decode(CharBuffer.wrap(encoded), output); decoder.finalize(output); output.flip(); return ByteUtil.toArray(output); } } cryptacular-1.2.5/src/main/java/org/cryptacular/util/HashUtil.java000066400000000000000000000221731422604312300251670ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.util; import java.io.IOException; import java.io.InputStream; import java.util.Arrays; import org.bouncycastle.crypto.Digest; import org.bouncycastle.crypto.digests.SHA1Digest; import org.bouncycastle.crypto.digests.SHA256Digest; import org.bouncycastle.crypto.digests.SHA3Digest; import org.bouncycastle.crypto.digests.SHA512Digest; import org.cryptacular.CryptoException; import org.cryptacular.SaltedHash; import org.cryptacular.StreamException; import org.cryptacular.io.Resource; /** * Utility class for computing cryptographic hashes. * * @author Middleware Services */ public final class HashUtil { /** Private constructor of utility class. */ private HashUtil() {} /** * Computes the hash of the given data using the given algorithm. A salted hash may be produced as follows: * *
       // data is a byte array containing raw data to digest
       final byte[] salt = new RBGNonce(16).generate();
       final byte[] hash = HashUtil.hash(new SHA1Digest(), data, salt);
   * 
* * @param digest Hash algorithm. * @param data Data to hash. Supported types are byte[], {@link CharSequence} ,{@link InputStream}, and * {@link Resource}. Character data is processed in the UTF-8 character set; if another * character set is desired, the caller should convert to byte[] and provide the resulting * bytes. * * @return Byte array of length {@link Digest#getDigestSize()} containing hash output. * * @throws CryptoException on hash computation errors. * @throws StreamException on stream IO errors. */ public static byte[] hash(final Digest digest, final Object... data) throws CryptoException, StreamException { for (Object o : data) { if (o instanceof byte[]) { final byte[] bytes = (byte[]) o; digest.update(bytes, 0, bytes.length); } else if (o instanceof String) { final byte[] bytes = ByteUtil.toBytes((String) o); digest.update(bytes, 0, bytes.length); } else if (o instanceof InputStream) { hashStream(digest, (InputStream) o); } else if (o instanceof Resource) { final InputStream in; try { in = ((Resource) o).getInputStream(); } catch (IOException e) { throw new StreamException(e); } hashStream(digest, in); } else { throw new IllegalArgumentException("Invalid input data type " + o); } } final byte[] output = new byte[digest.getDigestSize()]; try { digest.doFinal(output, 0); } catch (RuntimeException e) { throw new CryptoException("Hash computation error", e); } return output; } /** * Computes the iterated hash of the given data using the given algorithm. The following example demonstrates a * typical usage pattern, a salted hash with 10 rounds: * *
       // data is a byte array containing raw data to digest
       final byte[] salt = new RBGNonce(16).generate();
       final byte[] hash = HashUtil.hash(new SHA1Digest(), 10, data, salt);
   * 
* * @param digest Hash algorithm. * @param iterations Number of hash rounds. Must be positive value. * @param data Data to hash. Supported types are byte[], {@link CharSequence} ,{@link InputStream}, and * {@link Resource}. Character data is processed in the UTF-8 character set; if another * character set is desired, the caller should convert to byte[] and provide the resulting * bytes. * * @return Byte array of length {@link Digest#getDigestSize()} containing hash output. * * @throws CryptoException on hash computation errors. * @throws StreamException on stream IO errors. */ public static byte[] hash(final Digest digest, final int iterations, final Object... data) throws CryptoException, StreamException { if (iterations < 1) { throw new IllegalArgumentException("Iterations must be positive"); } final byte[] output = hash(digest, data); try { for (int i = 1; i < iterations; i++) { digest.update(output, 0, output.length); digest.doFinal(output, 0); } } catch (RuntimeException e) { throw new CryptoException("Hash computation error", e); } return output; } /** * Determines whether the hash of the given input equals a known value. * * @param digest Hash algorithm. * @param hash Hash to compare with. If the length of the array is greater than the length of the digest output, * anything beyond the digest length is considered salt data that is hashed after the * input data. * @param iterations Number of hash rounds. * @param data Data to hash. * * @return True if the hash of the data under the given digest is equal to the hash, false otherwise. * * @throws CryptoException on hash computation errors. * @throws StreamException on stream IO errors. */ public static boolean compareHash(final Digest digest, final byte[] hash, final int iterations, final Object... data) throws CryptoException, StreamException { if (hash.length > digest.getDigestSize()) { final byte[] hashPart = Arrays.copyOfRange(hash, 0, digest.getDigestSize()); final byte[] saltPart = Arrays.copyOfRange(hash, digest.getDigestSize(), hash.length); final Object[] dataWithSalt = Arrays.copyOf(data, data.length + 1); dataWithSalt[data.length] = saltPart; return Arrays.equals(hash(digest, iterations, dataWithSalt), hashPart); } return Arrays.equals(hash(digest, iterations, data), hash); } /** * Determines whether the salted hash of the given input equals a known hash value. * * @param digest Hash algorithm. * @param hash Salted hash data. * @param iterations Number of hash rounds. * @param saltAfterData True to apply salt after data, false to apply salt before data. * @param data Data to hash, which should NOT include the salt value. * * @return True if the hash of the data under the given digest is equal to the hash, false otherwise. * * @throws CryptoException on hash computation errors. * @throws StreamException on stream IO errors. */ public static boolean compareHash( final Digest digest, final SaltedHash hash, final int iterations, final boolean saltAfterData, final Object... data) throws CryptoException, StreamException { final Object[] dataWithSalt; if (saltAfterData) { dataWithSalt = Arrays.copyOf(data, data.length + 1); dataWithSalt[data.length] = hash.getSalt(); } else { dataWithSalt = new Object[data.length + 1]; dataWithSalt[0] = hash.getSalt(); System.arraycopy(data, 0, dataWithSalt, 1, data.length); } return Arrays.equals(hash(digest, iterations, dataWithSalt), hash.getHash()); } /** * Produces the SHA-1 hash of the given data. * * @param data Data to hash. See {@link #hash(Digest, Object...)} for supported inputs. * * @return 20-byte array containing hash output. * * @see #hash(Digest, Object...) */ public static byte[] sha1(final Object... data) { return hash(new SHA1Digest(), data); } /** * Produces the SHA-256 hash of the given data. * * @param data Data to hash. See {@link #hash(Digest, Object...)} for supported inputs. * * @return 32-byte array containing hash output. * * @see #hash(Digest, Object...) */ public static byte[] sha256(final Object... data) { return hash(new SHA256Digest(), data); } /** * Produces the SHA-512 hash of the given data. * * @param data Data to hash. See {@link #hash(Digest, Object...)} for supported inputs. * * @return 64-byte array containing hash output. * * @see #hash(Digest, Object...) */ public static byte[] sha512(final Object... data) { return hash(new SHA512Digest(), data); } /** * Produces the SHA-3 hash of the given data. * * @param bitLength One of the supported SHA-3 output bit lengths: 224, 256, 384, or 512. * @param data Data to hash. See {@link #hash(Digest, Object...)} for supported inputs. * * @return Byte array of size bitLength containing hash output. * * @see #hash(Digest, Object...) */ public static byte[] sha3(final int bitLength, final Object... data) { return hash(new SHA3Digest(bitLength), data); } /** * Digests the data in the given stream. Note this method does not finalize the digest process by calling {@link * Digest#doFinal(byte[], int)}. * * @param digest Digest algorithm. * @param in Input stream containing data to hash. */ private static void hashStream(final Digest digest, final InputStream in) { final byte[] buffer = new byte[StreamUtil.CHUNK_SIZE]; int length; try { while ((length = in.read(buffer)) > 0) { digest.update(buffer, 0, length); } } catch (IOException e) { throw new StreamException(e); } } } cryptacular-1.2.5/src/main/java/org/cryptacular/util/KeyPairUtil.java000066400000000000000000000400211422604312300256400ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.util; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.InputStream; import java.math.BigInteger; import java.security.PrivateKey; import java.security.PublicKey; import java.security.interfaces.DSAPrivateKey; import java.security.interfaces.DSAPublicKey; import java.security.interfaces.ECPrivateKey; import java.security.interfaces.ECPublicKey; import java.security.interfaces.RSAPrivateKey; import java.security.interfaces.RSAPublicKey; import org.bouncycastle.crypto.digests.SHA256Digest; import org.bouncycastle.crypto.params.AsymmetricKeyParameter; import org.bouncycastle.crypto.params.DSAParameters; import org.bouncycastle.crypto.params.DSAPrivateKeyParameters; import org.bouncycastle.crypto.params.DSAPublicKeyParameters; import org.bouncycastle.crypto.params.RSAKeyParameters; import org.bouncycastle.crypto.signers.DSASigner; import org.bouncycastle.crypto.signers.ECDSASigner; import org.bouncycastle.crypto.signers.RSADigestSigner; import org.bouncycastle.jcajce.provider.asymmetric.util.ECUtil; import org.cryptacular.EncodingException; import org.cryptacular.StreamException; import org.cryptacular.adapter.Converter; import org.cryptacular.asn.OpenSSLPrivateKeyDecoder; import org.cryptacular.asn.PKCS8PrivateKeyDecoder; import org.cryptacular.asn.PublicKeyDecoder; /** * Utility methods for public/private key pairs used for asymmetric encryption. * * @author Middleware Services */ public final class KeyPairUtil { /** Data used to verify key pairs. */ private static final byte[] SIGN_BYTES = ByteUtil.toBytes("Mr. Watson--come here--I want to see you."); /** Private constructor of utility class. */ private KeyPairUtil() {} /** * Gets the length in bits of a public key where key size is dependent on the particulars of the algorithm. * *
    *
  • DSA - length of p
  • *
  • EC - length of p for prime fields, m for binary fields
  • *
  • RSA - length of modulus
  • *
* * @param pubKey Public key. * * @return Size of the key in bits. */ public static int length(final PublicKey pubKey) { final int size; if (pubKey instanceof DSAPublicKey) { size = ((DSAPublicKey) pubKey).getParams().getP().bitLength(); } else if (pubKey instanceof RSAPublicKey) { size = ((RSAPublicKey) pubKey).getModulus().bitLength(); } else if (pubKey instanceof ECPublicKey) { size = ((ECPublicKey) pubKey).getParams().getCurve().getField().getFieldSize(); } else { throw new IllegalArgumentException(pubKey + " not supported."); } return size; } /** * Gets the length in bits of a private key where key size is dependent on the particulars of the algorithm. * *
    *
  • DSA - length of q in bits
  • *
  • EC - length of p for prime fields, m for binary fields
  • *
  • RSA - modulus length in bits
  • *
* * @param privKey Private key. * * @return Size of the key in bits. */ public static int length(final PrivateKey privKey) { final int size; if (privKey instanceof DSAPrivateKey) { size = ((DSAPrivateKey) privKey).getParams().getQ().bitLength(); } else if (privKey instanceof RSAPrivateKey) { size = ((RSAPrivateKey) privKey).getModulus().bitLength(); } else if (privKey instanceof ECPrivateKey) { size = ((ECPrivateKey) privKey).getParams().getCurve().getField().getFieldSize(); } else { throw new IllegalArgumentException(privKey + " not supported."); } return size; } /** * Determines whether the given public and private keys form a proper key pair by computing and verifying a digital * signature with the keys. * * @param pubKey DSA, RSA or EC public key. * @param privKey DSA, RSA, or EC private key. * * @return True if the keys form a functioning keypair, false otherwise. Errors during signature verification are * treated as false. * * @throws org.cryptacular.CryptoException on key validation errors. */ public static boolean isKeyPair(final PublicKey pubKey, final PrivateKey privKey) throws org.cryptacular.CryptoException { final String alg = pubKey.getAlgorithm(); if (!alg.equals(privKey.getAlgorithm())) { return false; } // Dispatch onto the algorithm-specific method final boolean result; switch (alg) { case "DSA": result = isKeyPair((DSAPublicKey) pubKey, (DSAPrivateKey) privKey); break; case "RSA": result = isKeyPair((RSAPublicKey) pubKey, (RSAPrivateKey) privKey); break; case "EC": result = isKeyPair((ECPublicKey) pubKey, (ECPrivateKey) privKey); break; default: throw new IllegalArgumentException(alg + " not supported."); } return result; } /** * Determines whether the given DSA public and private keys form a proper key pair by computing and verifying a * digital signature with the keys. * * @param pubKey DSA public key. * @param privKey DSA private key. * * @return True if the keys form a functioning keypair, false otherwise. Errors during signature verification are * treated as false. * * @throws org.cryptacular.CryptoException on key validation errors. */ public static boolean isKeyPair(final DSAPublicKey pubKey, final DSAPrivateKey privKey) throws org.cryptacular.CryptoException { final DSASigner signer = new DSASigner(); final DSAParameters params = new DSAParameters( privKey.getParams().getP(), privKey.getParams().getQ(), privKey.getParams().getG()); try { signer.init(true, new DSAPrivateKeyParameters(privKey.getX(), params)); final BigInteger[] sig = signer.generateSignature(SIGN_BYTES); signer.init(false, new DSAPublicKeyParameters(pubKey.getY(), params)); return signer.verifySignature(SIGN_BYTES, sig[0], sig[1]); } catch (RuntimeException e) { throw new org.cryptacular.CryptoException("Signature computation error", e); } } /** * Determines whether the given RSA public and private keys form a proper key pair by computing and verifying a * digital signature with the keys. * * @param pubKey RSA public key. * @param privKey RSA private key. * * @return True if the keys form a functioning keypair, false otherwise. Errors during signature verification are * treated as false. * * @throws org.cryptacular.CryptoException on key validation errors. */ public static boolean isKeyPair(final RSAPublicKey pubKey, final RSAPrivateKey privKey) throws org.cryptacular.CryptoException { final RSADigestSigner signer = new RSADigestSigner(new SHA256Digest()); try { signer.init(true, new RSAKeyParameters(true, privKey.getModulus(), privKey.getPrivateExponent())); signer.update(SIGN_BYTES, 0, SIGN_BYTES.length); final byte[] sig = signer.generateSignature(); signer.init(false, new RSAKeyParameters(false, pubKey.getModulus(), pubKey.getPublicExponent())); signer.update(SIGN_BYTES, 0, SIGN_BYTES.length); return signer.verifySignature(sig); } catch (Exception e) { throw new org.cryptacular.CryptoException("Signature computation error", e); } } /** * Determines whether the given EC public and private keys form a proper key pair by computing and verifying a digital * signature with the keys. * * @param pubKey EC public key. * @param privKey EC private key. * * @return True if the keys form a functioning keypair, false otherwise. Errors during signature verification are * treated as false. * * @throws org.cryptacular.CryptoException on key validation errors. */ public static boolean isKeyPair(final ECPublicKey pubKey, final ECPrivateKey privKey) throws org.cryptacular.CryptoException { final ECDSASigner signer = new ECDSASigner(); try { signer.init(true, ECUtil.generatePrivateKeyParameter(privKey)); final BigInteger[] sig = signer.generateSignature(SIGN_BYTES); signer.init(false, ECUtil.generatePublicKeyParameter(pubKey)); return signer.verifySignature(SIGN_BYTES, sig[0], sig[1]); } catch (Exception e) { throw new org.cryptacular.CryptoException("Signature computation error", e); } } /** * Reads an encoded private key from a file at the given path. Both PKCS#8 and OpenSSL "traditional" formats are * supported in DER or PEM encoding. See {@link #decodePrivateKey(byte[])} for supported asymmetric algorithms. * * @param path Path to private key file. * * @return Private key. * * @throws EncodingException on key encoding errors. * @throws StreamException on IO errors reading data from file. */ public static PrivateKey readPrivateKey(final String path) throws EncodingException, StreamException { return readPrivateKey(new File(path)); } /** * Reads an encoded private key from a file. Both PKCS#8 and OpenSSL "traditional" formats are supported in DER or PEM * encoding. See {@link #decodePrivateKey(byte[])} for supported asymmetric algorithms. * * @param file Private key file. * * @return Private key. * * @throws EncodingException on key encoding errors. * @throws StreamException on IO errors reading data from file. */ public static PrivateKey readPrivateKey(final File file) throws EncodingException, StreamException { try { return readPrivateKey(new FileInputStream(file)); } catch (FileNotFoundException e) { throw new StreamException("File not found: " + file); } } /** * Reads an encoded private key from an input stream. Both PKCS#8 and OpenSSL "traditional" formats are supported in * DER or PEM encoding. See {@link #decodePrivateKey(byte[])} for supported asymmetric algorithms. The {@link * InputStream} parameter is closed by this method. * * @param in Input stream containing private key data. * * @return Private key. * * @throws EncodingException on key encoding errors. * @throws StreamException on IO errors reading data from file. */ public static PrivateKey readPrivateKey(final InputStream in) throws EncodingException, StreamException { return decodePrivateKey(StreamUtil.readAll(in)); } /** * Reads an encrypted private key from a file at the given path. Both PKCS#8 and OpenSSL "traditional" formats are * supported in DER or PEM encoding. See {@link #decodePrivateKey(byte[])} for supported asymmetric algorithms. * * @param path Path to private key file. * @param password Password used to encrypt private key. * * @return Private key. * * @throws EncodingException on key encoding errors. * @throws StreamException on IO errors. */ public static PrivateKey readPrivateKey(final String path, final char[] password) throws EncodingException, StreamException { return readPrivateKey(new File(path), password); } /** * Reads an encrypted private key from a file. Both PKCS#8 and OpenSSL "traditional" formats are supported in DER or * PEM encoding. See {@link #decodePrivateKey(byte[])} for supported asymmetric algorithms. * * @param file Private key file. * @param password Password used to encrypt private key. * * @return Private key. * * @throws EncodingException on key encoding errors. * @throws StreamException on IO errors. */ public static PrivateKey readPrivateKey(final File file, final char[] password) throws EncodingException, StreamException { try { return readPrivateKey(new FileInputStream(file), password); } catch (FileNotFoundException e) { throw new StreamException("File not found: " + file); } } /** * Reads an encrypted private key from an input stream. Both PKCS#8 and OpenSSL "traditional" formats are supported in * DER or PEM encoding. See {@link #decodePrivateKey(byte[])} for supported asymmetric algorithms. The {@link * InputStream} parameter is closed by this method. * * @param in Input stream containing private key data. * @param password Password used to encrypt private key. * * @return Private key. * * @throws EncodingException on key encoding errors. * @throws StreamException on IO errors. */ public static PrivateKey readPrivateKey(final InputStream in, final char[] password) throws EncodingException, StreamException { return decodePrivateKey(StreamUtil.readAll(in), password); } /** * Decodes an encoded private key in either PKCS#8 or OpenSSL "traditional" format in either DER or PEM encoding. Keys * from the following asymmetric algorithms are supported: * *
    *
  • DSA
  • *
  • RSA
  • *
  • Elliptic curve
  • *
* * @param encodedKey Encoded private key data. * * @return Private key. * * @throws EncodingException on key encoding errors. */ public static PrivateKey decodePrivateKey(final byte[] encodedKey) throws EncodingException { return decodePrivateKey(encodedKey, null); } /** * Decodes an encrypted private key. The following formats are supported: * *
    *
  • DER or PEM encoded PKCS#8 format
  • *
  • PEM encoded OpenSSL "traditional" format
  • *
* *

Keys from the following asymmetric algorithms are supported:

* *
    *
  • DSA
  • *
  • RSA
  • *
  • Elliptic curve
  • *
* * @param encryptedKey Encrypted private key data. * @param password Password used to encrypt private key. * * @return Private key. * * @throws EncodingException on key encoding errors. */ public static PrivateKey decodePrivateKey(final byte[] encryptedKey, final char[] password) throws EncodingException { AsymmetricKeyParameter key; try { final PKCS8PrivateKeyDecoder decoder = new PKCS8PrivateKeyDecoder(); key = decoder.decode(encryptedKey, password); } catch (RuntimeException e) { final OpenSSLPrivateKeyDecoder decoder = new OpenSSLPrivateKeyDecoder(); key = decoder.decode(encryptedKey, password); } return Converter.convertPrivateKey(key); } /** * Reads a DER or PEM-encoded public key from a file. * * @param path Path to DER or PEM-encoded public key file. * * @return Public key. * * @throws EncodingException on key encoding errors. * @throws StreamException on IO errors. */ public static PublicKey readPublicKey(final String path) throws EncodingException, StreamException { return readPublicKey(new File(path)); } /** * Reads a DER or PEM-encoded public key from a file. * * @param file DER or PEM-encoded public key file. * * @return Public key. * * @throws EncodingException on key encoding errors. * @throws StreamException on IO errors. */ public static PublicKey readPublicKey(final File file) throws EncodingException, StreamException { try { return readPublicKey(new FileInputStream(file)); } catch (FileNotFoundException e) { throw new StreamException("File not found: " + file); } } /** * Reads a DER or PEM-encoded public key from data in the given stream. The {@link InputStream} parameter is closed by * this method. * * @param in Input stream containing an encoded key. * * @return Public key. * * @throws EncodingException on key encoding errors. * @throws StreamException on IO errors. */ public static PublicKey readPublicKey(final InputStream in) throws EncodingException, StreamException { return decodePublicKey(StreamUtil.readAll(in)); } /** * Decodes public keys formatted in an X.509 SubjectPublicKeyInfo structure in either PEM or DER encoding. * * @param encoded Encoded public key bytes. * * @return Public key. * * @throws EncodingException on key encoding errors. */ public static PublicKey decodePublicKey(final byte[] encoded) throws EncodingException { return Converter.convertPublicKey(new PublicKeyDecoder().decode(encoded)); } } cryptacular-1.2.5/src/main/java/org/cryptacular/util/NonceUtil.java000066400000000000000000000156041422604312300253470ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.util; import java.lang.reflect.Method; import java.security.SecureRandom; import javax.crypto.SecretKey; import org.bouncycastle.crypto.BlockCipher; import org.bouncycastle.crypto.Digest; import org.bouncycastle.crypto.digests.SHA256Digest; import org.bouncycastle.crypto.prng.EntropySource; import org.bouncycastle.crypto.prng.SP800SecureRandom; import org.bouncycastle.crypto.prng.drbg.HashSP800DRBG; import org.bouncycastle.crypto.prng.drbg.SP80090DRBG; import org.cryptacular.generator.sp80038a.EncryptedNonce; import org.cryptacular.generator.sp80038d.RBGNonce; /** * Utility class for generating secure nonce and initialization vectors. * * @author Middleware Services */ public final class NonceUtil { /** Class-wide random source. */ private static final SecureRandom SECURE_RANDOM = new SecureRandom(); /** Seed random source. */ static { // Call nextBytes to force seeding via default process SECURE_RANDOM.nextBytes(new byte[1]); } /** Private constructor of utility class. */ private NonceUtil() {} /** * Generates a nonce of the given size by repetitively concatenating system timestamps (i.e. {@link * System#nanoTime()}) up to the required size. * * @param length Positive number of bytes in nonce. * * @return Nonce bytes. */ public static byte[] timestampNonce(final int length) { if (length <= 0) { throw new IllegalArgumentException(length + " is invalid. Length must be positive."); } final byte[] nonce = new byte[length]; int count = 0; long timestamp; while (count < length) { timestamp = System.nanoTime(); for (int i = 0; i < 8 && count < length; i++) { nonce[count++] = (byte) (timestamp & 0xFF); timestamp >>= 8; } } return nonce; } /** * Generates a random nonce of the given length in bytes. * * @param length Positive number of bytes in nonce. * * @return Nonce bytes. */ public static byte[] randomNonce(final int length) { if (length <= 0) { throw new IllegalArgumentException(length + " is invalid. Length must be positive."); } final byte[] nonce = new byte[length]; SECURE_RANDOM.nextBytes(nonce); return nonce; } /** * Creates a new entropy source that wraps a {@link SecureRandom} to produce random bytes. * * @param length Size of entropy blocks. * * @return New random entropy source. */ public static EntropySource randomEntropySource(final int length) { return new EntropySource() { @Override public boolean isPredictionResistant() { return true; } @Override public byte[] getEntropy() { final byte[] bytes = new byte[length]; SECURE_RANDOM.nextBytes(bytes); return bytes; } @Override public int entropySize() { return length; } }; } /** * Generates a nonce/IV using the strategy described in NIST SP-800-38d, section 8.2.2, "RBG-based * Construction". The implementation uses a hash-based DRBG based on a SHA-256 digest, and uses random data for all * bits of the nonce; that is, the fixed field is null. * *

This nonce generation strategy is suitable for GCM ciphers.

* * @param length Number of bytes in nonce; MUST be 12 or more. * * @return Nonce bytes. */ public static byte[] nist80038d(final int length) { return new RBGNonce(length).generate(); } /** * Generates a random IV according to NIST SP-800-63a, appendix C, method 1 * (encrypted nonce), suitable for use with any block cipher mode described in that standard. This method uses an * instance of {@link EncryptedNonce} for the implementation. * * @param cipher Block cipher. * @param key Encryption key intended for use with IV. * * @return Cipher block size number of random bytes. * * @see EncryptedNonce */ public static byte[] nist80063a(final BlockCipher cipher, final SecretKey key) { BlockCipher raw = cipher; // Get the underlying cipher if there is one final Method method = ReflectUtil.getMethod(cipher.getClass(), "getUnderlyingCipher"); if (method != null) { raw = (BlockCipher) ReflectUtil.invoke(cipher, method); } return new EncryptedNonce(raw, key).generate(); } /** * Generates a random IV according to NIST SP-800-63a, appendix C, method 2 * (pseudorandom), suitable for use with any block cipher mode described in that standard. * * @param prng NIST SP800-63a approved pseudorandom number generator. * @param blockSize Cipher block size in bytes. * * @return Cipher block size number of random bytes. */ public static byte[] nist80063a(final SP800SecureRandom prng, final int blockSize) { prng.setSeed(randomNonce(blockSize)); final byte[] iv = new byte[blockSize]; prng.nextBytes(iv); return iv; } /** * Generates a random IV according to NIST SP-800-63a, appendix C, method 2 * (pseudorandom), suitable for use with any block cipher mode described in that standard. Uses an instance of {@link * RBGNonce} internally with length equal to block size of given cipher. * * @param cipher Block cipher. * * @return Cipher block size number of random bytes. * * @see RBGNonce */ public static byte[] nist80063a(final BlockCipher cipher) { return new RBGNonce(cipher.getBlockSize()).generate(); } /** * Creates a new DRBG instance based on a SHA-256 digest. * * @param length Length in bits of values to be produced by DRBG instance. * * @return New DRGB instance. */ public static SP80090DRBG newRBG(final int length) { return newRBG(new SHA256Digest(), length); } /** * Creates a new hash-based DRBG instance that uses the given digest as the pseudorandom source. * * @param digest Digest algorithm. * @param length Length in bits of values to be produced by DRBG instance. * * @return New DRGB instance. */ public static SP80090DRBG newRBG(final Digest digest, final int length) { return newRBG(digest, length, randomEntropySource(length)); } /** * Creates a new hash-based DRBG instance that uses the given digest as the pseudorandom source. * * @param digest Digest algorithm. * @param length Length in bits of values to be produced by DRBG instance. * @param es Entropy source. * * @return New DRGB instance. */ public static SP80090DRBG newRBG(final Digest digest, final int length, final EntropySource es) { return new HashSP800DRBG( digest, length, es, Thread.currentThread().getName().getBytes(), NonceUtil.timestampNonce(8)); } } cryptacular-1.2.5/src/main/java/org/cryptacular/util/PemUtil.java000066400000000000000000000105261422604312300250240ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.util; import java.nio.ByteBuffer; import java.nio.CharBuffer; import java.util.regex.Pattern; import org.cryptacular.codec.Base64Decoder; /** * Utility class with helper methods for common PEM encoding operations. * * @author Middleware Services */ public final class PemUtil { /** Line length. */ public static final int LINE_LENGTH = 64; /** PEM encoding header start string. */ public static final String HEADER_BEGIN = "-----BEGIN"; /** PEM encoding footer start string. */ public static final String FOOTER_END = "-----END"; /** Procedure type tag for PEM-encoded private key in OpenSSL format. */ public static final String PROC_TYPE = "Proc-Type:"; /** Decryption infor tag for PEM-encoded private key in OpenSSL format. */ public static final String DEK_INFO = "DEK-Info:"; /** Pattern used to split multiple PEM-encoded objects in a single file. */ private static final Pattern PEM_SPLITTER = Pattern.compile("-----(?:BEGIN|END) [A-Z ]+-----"); /** Pattern used to a file by line terminator. */ private static final Pattern LINE_SPLITTER = Pattern.compile("[\r\n]+"); /** Private constructor of utility class. */ private PemUtil() {} /** * Determines whether the data in the given byte array is base64-encoded data of PEM encoding. The determination is * made using as little data from the given array as necessary to make a reasonable determination about encoding. * * @param data Data to test for PEM encoding * * @return True if data appears to be PEM encoded, false otherwise. */ public static boolean isPem(final byte[] data) { final String start = new String(data, 0, 10, ByteUtil.ASCII_CHARSET).trim(); if (!start.startsWith(HEADER_BEGIN) && !start.startsWith(PROC_TYPE)) { // Check all bytes in first line to make sure they are in the range // of base64 character set encoding for (int i = 0; i < LINE_LENGTH; i++) { if (!isBase64Char(data[i])) { // Last two bytes may be padding character '=' (61) if (i > LINE_LENGTH - 3) { if (data[i] != 61) { return false; } } else { return false; } } } } return true; } /** * Determines whether the given byte represents an ASCII character in the character set for base64 encoding. * * @param b Byte to test. * * @return True if the byte represents an ASCII character in the set of valid characters for base64 encoding, false * otherwise. The padding character '=' is not considered valid since it may only appear at the end of a * base64 encoded value. */ public static boolean isBase64Char(final byte b) { return !(b < 47 || b > 122 || b > 57 && b < 65 || b > 90 && b < 97) || b == 43; } /** * Decodes a PEM-encoded cryptographic object into the raw bytes of its ASN.1 encoding. Header/footer data and * metadata info, e.g. Proc-Type, are ignored. * * @param pem Bytes of PEM-encoded data to decode. * * @return ASN.1 encoded bytes. */ public static byte[] decode(final byte[] pem) { return decode(new String(pem, ByteUtil.ASCII_CHARSET)); } /** * Decodes one or more PEM-encoded cryptographic objects into the raw bytes of their ASN.1 encoding. All header and * metadata, e.g. Proc-Type, are ignored. If multiple cryptographic objects are represented, the decoded bytes of * each object are concatenated together and returned. * * @param pem PEM-encoded data to decode. * * @return ASN.1 encoded bytes. */ public static byte[] decode(final String pem) { final Base64Decoder decoder = new Base64Decoder(); final CharBuffer buffer = CharBuffer.allocate(pem.length()); final ByteBuffer output = ByteBuffer.allocate(pem.length() * 3 / 4); // There may be multiple PEM-encoded objects in the input for (String object : PEM_SPLITTER.split(pem)) { buffer.clear(); for (String line : LINE_SPLITTER.split(object)) { if (line.startsWith(DEK_INFO) || line.startsWith(PROC_TYPE)) { continue; } buffer.append(line); } buffer.flip(); decoder.decode(buffer, output); decoder.finalize(output); } output.flip(); return ByteUtil.toArray(output); } } cryptacular-1.2.5/src/main/java/org/cryptacular/util/ReflectUtil.java000066400000000000000000000033571422604312300256730ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.util; import java.lang.reflect.Method; import java.util.HashMap; import java.util.Map; /** * Reflection utilities. * * @author Middleware Services */ public final class ReflectUtil { /** Method cache. */ private static final Map METHOD_CACHE = new HashMap<>(); /** Private constructor of utility class. */ private ReflectUtil() {} /** * Gets the method defined on the target class. The method is cached to speed up subsequent lookups. * * @param target Target class that contains method. * @param name Method name. * @param parameters Method parameters. * * @return Method if found, otherwise null. */ public static Method getMethod(final Class target, final String name, final Class... parameters) { final String key = target.getName() + '.' + name; Method method = METHOD_CACHE.get(key); if (method != null) { return method; } try { method = target.getMethod(name, parameters); METHOD_CACHE.put(key, method); return method; } catch (NoSuchMethodException e) { return null; } } /** * Invokes the method on the target object with the given parameters. * * @param target Target class that contains method. * @param method Method to invoke on target. * @param parameters Method parameters. * * @return Method return value. A void method returns null. */ public static Object invoke(final Object target, final Method method, final Object... parameters) { try { return method.invoke(target, parameters); } catch (Exception e) { throw new RuntimeException("Failed invoking " + method, e); } } } cryptacular-1.2.5/src/main/java/org/cryptacular/util/StreamUtil.java000066400000000000000000000155171422604312300255430ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.util; import java.io.BufferedInputStream; import java.io.ByteArrayOutputStream; import java.io.CharArrayWriter; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.Reader; import java.io.Writer; import org.bouncycastle.util.io.Streams; import org.cryptacular.StreamException; import org.cryptacular.io.ChunkHandler; /** * Utility methods for stream handling. * * @author Middleware Services */ public final class StreamUtil { /** * Buffer size of chunked operations, e.g. {@link #pipeAll(java.io.InputStream, java.io.OutputStream, * org.cryptacular.io.ChunkHandler)}. */ public static final int CHUNK_SIZE = 1024; /** Private method of utility class. */ private StreamUtil() {} /** * Reads all the data from the file at the given path. * * @param path Path to file. * * @return Byte array of data read from file. * * @throws StreamException on stream IO errors. */ public static byte[] readAll(final String path) throws StreamException { return readAll(new File(path)); } /** * Reads all the data from the given file. * * @param file File to read. * * @return Byte array of data read from file. * * @throws StreamException on stream IO errors. */ public static byte[] readAll(final File file) throws StreamException { final InputStream input = makeStream(file); try { return readAll(input, (int) file.length()); } finally { closeStream(input); } } /** * Reads all the data from the given input stream. * * @param input Input stream to read. * * @return Byte array of data read from stream. * * @throws StreamException on stream IO errors. */ public static byte[] readAll(final InputStream input) throws StreamException { return readAll(input, 1024); } /** * Reads all the data from the given input stream. * * @param input Input stream to read. * @param sizeHint Estimate of amount of data to be read in bytes. * * @return Byte array of data read from stream. * * @throws StreamException on stream IO errors. */ public static byte[] readAll(final InputStream input, final int sizeHint) throws StreamException { final ByteArrayOutputStream output = new ByteArrayOutputStream(sizeHint); try { Streams.pipeAll(input, output); } catch (IOException e) { throw new StreamException(e); } finally { closeStream(input); closeStream(output); } return output.toByteArray(); } /** * Reads all data from the given reader. * * @param reader Reader over character data. * * @return Data read from reader. * * @throws StreamException on stream IO errors. */ public static String readAll(final Reader reader) throws StreamException { return readAll(reader, 1024); } /** * Reads all data from the given reader. * * @param reader Reader over character data. * @param sizeHint Estimate of amount of data to be read in number of characters. * * @return Data read from reader. * * @throws StreamException on stream IO errors. */ public static String readAll(final Reader reader, final int sizeHint) throws StreamException { final CharArrayWriter writer = new CharArrayWriter(sizeHint); final char[] buffer = new char[CHUNK_SIZE]; int len; try { while ((len = reader.read(buffer)) > 0) { writer.write(buffer, 0, len); } } catch (IOException e) { throw new StreamException(e); } finally { closeReader(reader); closeWriter(writer); } return writer.toString(); } /** * Pipes an input stream into an output stream with chunked processing. * * @param in Input stream providing data to process. * @param out Output stream holding processed data. * @param handler Arbitrary handler for processing input stream. * * @throws StreamException on stream IO errors. */ public static void pipeAll(final InputStream in, final OutputStream out, final ChunkHandler handler) throws StreamException { final byte[] buffer = new byte[CHUNK_SIZE]; int count; try { while ((count = in.read(buffer)) > 0) { handler.handle(buffer, 0, count, out); } } catch (IOException e) { throw new StreamException(e); } } /** * Creates an input stream around the given file. * * @param file Input stream source. * * @return Input stream around file. * * @throws StreamException on stream IO errors. */ public static InputStream makeStream(final File file) throws StreamException { try { return new BufferedInputStream(new FileInputStream(file)); } catch (FileNotFoundException e) { throw new StreamException(file + " does not exist"); } } /** * Creates a reader around the given file that presumably contains character data. * * @param file Reader source. * * @return Reader around file. * * @throws StreamException on stream IO errors. */ public static Reader makeReader(final File file) throws StreamException { try { return new InputStreamReader(new BufferedInputStream(new FileInputStream(file))); } catch (FileNotFoundException e) { throw new StreamException(file + " does not exist"); } } /** * Closes the given stream and swallows exceptions that may arise during the process. * * @param in Input stream to close. */ public static void closeStream(final InputStream in) { try { in.close(); } catch (IOException e) { System.err.println("Error closing " + in + ": " + e); } } /** * Closes the given stream and swallows exceptions that may arise during the process. * * @param out Output stream to close. */ public static void closeStream(final OutputStream out) { try { out.close(); } catch (IOException e) { System.err.println("Error closing " + out + ": " + e); } } /** * Closes the given reader and swallows exceptions that may arise during the process. * * @param reader Reader to close. */ public static void closeReader(final Reader reader) { try { reader.close(); } catch (IOException e) { System.err.println("Error closing " + reader + ": " + e); } } /** * Closes the given writer and swallows exceptions that may arise during the process. * * @param writer Writer to close. */ public static void closeWriter(final Writer writer) { try { writer.close(); } catch (IOException e) { System.err.println("Error closing " + writer + ": " + e); } } } cryptacular-1.2.5/src/main/java/org/cryptacular/x509/000077500000000000000000000000001422604312300223265ustar00rootroot00000000000000cryptacular-1.2.5/src/main/java/org/cryptacular/x509/ExtensionReader.java000066400000000000000000000247111422604312300262750ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.x509; import java.security.cert.X509Certificate; import java.util.ArrayList; import java.util.List; import org.bouncycastle.asn1.ASN1Encodable; import org.bouncycastle.asn1.ASN1OctetString; import org.bouncycastle.asn1.ASN1Primitive; import org.bouncycastle.asn1.ASN1Sequence; import org.bouncycastle.asn1.x509.AccessDescription; import org.bouncycastle.asn1.x509.AuthorityKeyIdentifier; import org.bouncycastle.asn1.x509.BasicConstraints; import org.bouncycastle.asn1.x509.DistributionPoint; import org.bouncycastle.asn1.x509.GeneralNames; import org.bouncycastle.asn1.x509.KeyPurposeId; import org.bouncycastle.asn1.x509.KeyUsage; import org.bouncycastle.asn1.x509.PolicyInformation; import org.bouncycastle.asn1.x509.SubjectKeyIdentifier; import org.cryptacular.EncodingException; /** * Reads X.509v3 extended properties from an {@link java.security.cert.X509Certificate} object. The available properties * are described in section 4.2 of RFC 2459, http://www.faqs.org/rfcs/rfc2459.html. * * @author Middleware Services */ public final class ExtensionReader { /** The X509Certificate whose extension fields will be read. */ private final X509Certificate certificate; /** * Creates a new instance that can read extension fields from the given X.509 certificate. * * @param cert Certificate to read. */ public ExtensionReader(final X509Certificate cert) { certificate = cert; } /** * Reads the value of the extension given by OID or name as defined in section 4.2 of RFC 2459. * * @param extensionOidOrName OID or extension name, e.g. 2.5.29.14 orSubjectK eyIdentifier. In the case of extension * name, the name is case-sensitive and follows the conventions in RFC 2459. * * @return Extension type containing data from requested extension field. * * @throws EncodingException On certificate field parse errors. */ public ASN1Encodable read(final String extensionOidOrName) throws EncodingException { if (extensionOidOrName == null) { throw new IllegalArgumentException("extensionOidOrName cannot be null."); } if (extensionOidOrName.contains(".")) { return read(ExtensionType.fromOid(extensionOidOrName)); } else { return read(ExtensionType.fromName(extensionOidOrName)); } } /** * Reads the value of the given certificate extension field. * * @param extension Extension to read from certificate. * * @return Extension type containing data from requested extension field. * * @throws EncodingException On certificate field parse errors. */ public ASN1Encodable read(final ExtensionType extension) { byte[] data = certificate.getExtensionValue(extension.getOid()); if (data == null) { return null; } try { ASN1Encodable der = ASN1Primitive.fromByteArray(data); if (der instanceof ASN1OctetString) { // Strip off octet string "wrapper" data = ((ASN1OctetString) der).getOctets(); der = ASN1Primitive.fromByteArray(data); } return der; } catch (Exception e) { throw new EncodingException("ASN.1 parse error", e); } } /** * Reads the value of the SubjectAlternativeName extension field of the certificate. * * @return Collection of subject alternative names or null if the certificate does not define this extension field. * Note that an empty collection of names is different from a null return value; in the former case the field * is defined but empty, whereas in the latter the field is not defined on the certificate. * * @throws EncodingException On certificate field parse errors. */ public GeneralNames readSubjectAlternativeName() throws EncodingException { try { return GeneralNames.getInstance(read(ExtensionType.SubjectAlternativeName)); } catch (RuntimeException e) { throw new EncodingException("GeneralNames parse error", e); } } /** * Reads the value of the IssuerAlternativeName extension field of the certificate. * * @return Collection of issuer alternative names or null if the certificate does not define this extension field. * Note that an empty collection of names is different from a null return value; in the former case the field * is defined but empty, whereas in the latter the field is not defined on the certificate. * * @throws EncodingException On certificate field parse errors. */ public GeneralNames readIssuerAlternativeName() throws EncodingException { try { return GeneralNames.getInstance(read(ExtensionType.IssuerAlternativeName)); } catch (RuntimeException e) { throw new EncodingException("GeneralNames parse error", e); } } /** * Reads the value of the BasicConstraints extension field of the certificate. * * @return Basic constraints defined on certificate or null if the certificate does not define the field. * * @throws EncodingException On certificate field parse errors. */ public BasicConstraints readBasicConstraints() throws EncodingException { try { return BasicConstraints.getInstance(read(ExtensionType.BasicConstraints)); } catch (RuntimeException e) { throw new EncodingException("BasicConstraints parse error", e); } } /** * Reads the value of the CertificatePolicies extension field of the certificate. * * @return List of certificate policies defined on certificate or null if the certificate does not define the field. * * @throws EncodingException On certificate field parse errors. */ public List readCertificatePolicies() throws EncodingException { final ASN1Encodable data = read(ExtensionType.CertificatePolicies); if (data == null) { return null; } try { final ASN1Sequence sequence = ASN1Sequence.getInstance(data); final List list = new ArrayList<>(sequence.size()); for (int i = 0; i < sequence.size(); i++) { list.add(PolicyInformation.getInstance(sequence.getObjectAt(i))); } return list; } catch (RuntimeException e) { throw new EncodingException("PolicyInformation parse error", e); } } /** * Reads the value of the SubjectKeyIdentifier extension field of the certificate. * * @return Subject key identifier. * * @throws EncodingException On certificate field parse errors. */ public SubjectKeyIdentifier readSubjectKeyIdentifier() throws EncodingException { try { return SubjectKeyIdentifier.getInstance(read(ExtensionType.SubjectKeyIdentifier)); } catch (RuntimeException e) { throw new EncodingException("SubjectKeyIdentifier parse error", e); } } /** * Reads the value of the AuthorityKeyIdentifier extension field of the certificate. * * @return Authority key identifier. * * @throws EncodingException On certificate field parse errors. */ public AuthorityKeyIdentifier readAuthorityKeyIdentifier() throws EncodingException { try { return AuthorityKeyIdentifier.getInstance(read(ExtensionType.AuthorityKeyIdentifier)); } catch (RuntimeException e) { throw new EncodingException("AuthorityKeyIdentifier parse error", e); } } /** * Reads the value of the KeyUsage extension field of the certificate. * * @return Key usage data or null if extension field is not defined. * * @throws EncodingException On certificate field parse errors. */ public KeyUsage readKeyUsage() throws EncodingException { try { return KeyUsage.getInstance(read(ExtensionType.KeyUsage)); } catch (RuntimeException e) { throw new EncodingException("KeyUsage parse error", e); } } /** * Reads the value of the ExtendedKeyUsage extension field of the certificate. * * @return List of supported extended key usages or null if extension is not defined. * * @throws EncodingException On certificate field parse errors. */ public List readExtendedKeyUsage() throws EncodingException { final ASN1Encodable data = read(ExtensionType.ExtendedKeyUsage); if (data == null) { return null; } try { final ASN1Sequence sequence = ASN1Sequence.getInstance(data); final List list = new ArrayList<>(sequence.size()); for (int i = 0; i < sequence.size(); i++) { list.add(KeyPurposeId.getInstance(sequence.getObjectAt(i))); } return list; } catch (RuntimeException e) { throw new EncodingException("KeyPurposeId parse error", e); } } /** * Reads the value of the CRLDistributionPoints extension field of the certificate. * * @return List of CRL distribution points or null if extension is not defined. * * @throws EncodingException On certificate field parse errors. */ public List readCRLDistributionPoints() throws EncodingException { final ASN1Encodable data = read(ExtensionType.CRLDistributionPoints); if (data == null) { return null; } try { final ASN1Sequence sequence = ASN1Sequence.getInstance(data); final List list = new ArrayList<>(sequence.size()); for (int i = 0; i < sequence.size(); i++) { list.add(DistributionPoint.getInstance(sequence.getObjectAt(i))); } return list; } catch (RuntimeException e) { throw new EncodingException("DistributionPoint parse error", e); } } /** * Reads the value of the AuthorityInformationAccess extension field of the certificate. * * @return List of access descriptions or null if extension is not defined. * * @throws EncodingException On certificate field parse errors. */ public List readAuthorityInformationAccess() throws EncodingException { final ASN1Encodable data = read(ExtensionType.AuthorityInformationAccess); if (data == null) { return null; } try { final ASN1Sequence sequence = ASN1Sequence.getInstance(data); final List list = new ArrayList<>(sequence.size()); for (int i = 0; i < sequence.size(); i++) { list.add(AccessDescription.getInstance(sequence.getObjectAt(i))); } return list; } catch (RuntimeException e) { throw new EncodingException("AccessDescription parse error", e); } } } cryptacular-1.2.5/src/main/java/org/cryptacular/x509/ExtensionType.java000066400000000000000000000067541422604312300260230ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.x509; /** * Enumeration of X.509v3 extension fields defined in section 4.2 of RFC 2459. * * @author Middleware Services * @version $Revision: 2745 $ */ public enum ExtensionType { /** AuthorityInfoAccess extension field. */ AuthorityInformationAccess("1.3.6.1.5.5.7.1.1", false), /** AuthorityKeyIdentifier extension field. */ AuthorityKeyIdentifier("2.5.29.35", false), /** BasicConstraints extension field. */ BasicConstraints("2.5.29.19", true), /** CertificatePolicies extension field. */ CertificatePolicies("2.5.29.32", false), /** CRLDistributionPoints extension field. */ CRLDistributionPoints("2.5.29.31", false), /** ExtendedKeyUsage extension field. */ ExtendedKeyUsage("2.5.29.37", false), /** IssuerAlternativeName extension field. */ IssuerAlternativeName("2.5.29.18", false), /** KeyUsage extension field. */ KeyUsage("2.5.29.15", true), /** NameConstraints extension field. */ NameConstraints("2.5.29.30", true), /** PolicyConstraints extension field. */ PolicyConstraints("2.5.29.36", false), /** PolicyMappings extension field. */ PolicyMappings("2.5.29.33", false), /** PrivateKeyUsage extension field. */ PrivateKeyUsagePeriod("2.5.29.16", false), /** SubjectAlternativeName extension field. */ SubjectAlternativeName("2.5.29.17", false), /** SubjectKeyIdentifier extension field. */ SubjectKeyIdentifier("2.5.29.14", false), /** SubjectDirectoryAttributes extension field. */ SubjectDirectoryAttributes("2.5.29.9", false); /** Oid value. */ private final String oid; /** Whether this extension is critical according to RFC 2459. */ private final boolean critical; /** * Creates a new type with the given OID value. * * @param oidString Extension OID value. * @param criticality True if extension MUST or SHOULD be marked critical under general circumstances, false * otherwise. */ ExtensionType(final String oidString, final boolean criticality) { oid = oidString; critical = criticality; } /** * Gets the extension by OID. * * @param oid Extension OID value. * * @return Extension with given OID value. * * @throws IllegalArgumentException If no extension with given OID exists. */ public static ExtensionType fromOid(final String oid) { for (ExtensionType ext : values()) { if (ext.getOid().equals(oid)) { return ext; } } throw new IllegalArgumentException("Invalid X.509v3 extension OID " + oid); } /** * Gets the extension by name. * * @param name Case-sensitive X.509v3 extension name. The acceptable case of extension names is governed by * conventions in RFC 2459. * * @return Extension with given name. * * @throws IllegalArgumentException If no extension with given name exists. */ public static ExtensionType fromName(final String name) { try { return ExtensionType.valueOf(ExtensionType.class, name); } catch (IllegalArgumentException e) { throw new IllegalArgumentException("Invalid X.509v3 extension name " + name); } } /** * @return True if extension MUST or SHOULD be marked critical under general circumstances according to RFC 2459, * false otherwise. */ public boolean isCritical() { return critical; } /** @return OID value of extension field. */ public String getOid() { return oid; } } cryptacular-1.2.5/src/main/java/org/cryptacular/x509/GeneralNameType.java000066400000000000000000000034011422604312300262070ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.x509; /** * Representation of the options in the CHOICE element describing various categories of the GeneralName * type defined in section 4.2.1.7 of RFC 2459. * * @author Middleware Services */ public enum GeneralNameType { /** otherName choice element. */ OtherName, /** rfc822Name choice element. */ RFC822Name, /** dNSName choice element. */ DNSName, /** x400Address choice element. */ X400Address, /** directoryName choice element. */ DirectoryName, /** ediPartyName choice element. */ EdiPartyName, /** uniformResourceIdentifier choice element. */ UniformResourceIdentifier, /** iPAddress choice element. */ IPAddress, /** registeredID choice element. */ RegisteredID; /** Minimum tag number for items in CHOICE definition. */ public static final int MIN_TAG_NUMBER = 0; /** Maximum tag number for items in CHOICE definition. */ public static final int MAX_TAG_NUMBER = 8; /** * Gets a name type from the value of the tag in the CHOICE element definition. * * @param tagNo Ordinal position of type in CHOICE definition in RFC 2459. * * @return Type corresponding to given tag number. * * @throws IllegalArgumentException If there is not general name type corresponding to the given tag number. */ public static GeneralNameType fromTagNumber(final int tagNo) { if (tagNo < MIN_TAG_NUMBER || tagNo > MAX_TAG_NUMBER) { throw new IllegalArgumentException("Invalid tag number " + tagNo); } for (GeneralNameType type : values()) { if (type.ordinal() == tagNo) { return type; } } throw new IllegalArgumentException("Invalid tag number " + tagNo); } } cryptacular-1.2.5/src/main/java/org/cryptacular/x509/KeyUsageBits.java000066400000000000000000000046431422604312300255370ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.x509; import java.util.BitSet; import org.bouncycastle.asn1.x509.KeyUsage; /** * Representation of the bit meanings in the KeyUsage BIT STRING type defined in section 4.2.1.3 of RFC * 2459. * * @author Middleware Services * @version $Revision: 2745 $ */ public enum KeyUsageBits { /** digitalSignature bit. */ DigitalSignature(7), /** nonRepudiation bit. */ NonRepudiation(6), /** keyEncipherment bit. */ KeyEncipherment(5), /** dataEncipherment bit. */ DataEncipherment(4), /** keyAgreement bit. */ KeyAgreement(3), /** keyCertSign bit. */ KeyCertSign(2), /** cRLSign bit. */ CRLSign(1), /** encipherOnly bit. */ EncipherOnly(0), /** decipherOnly bit. */ DecipherOnly(15); /** Bit mask offset. */ private final int offset; /** * Creates a bit flag with the given bit mask offset. * * @param offset Bit mask offset. */ KeyUsageBits(final int offset) { this.offset = offset; } /** @return Bit mask value. */ public int getMask() { return 1 << offset; } /** * Determines whether this key usage bit is set in the given key usage value. * * @param keyUsage BC key usage object. * * @return True if bit is set, false otherwise. */ public boolean isSet(final KeyUsage keyUsage) { return isSet(keyUsage.getBytes()); } /** * Determines whether this key usage bit is set in the given key usage bit string. * * @param bitString Key usage bit string as a byte array. * * @return True if bit is set, false otherwise. */ public boolean isSet(final byte[] bitString) { return BitSet.valueOf(bitString).get(offset); } /** * Determines whether this key usage bit is set in the given key usage bit string. * * @param bitString Key usage bit string as a big endian integer. * * @return True if bit is set, false otherwise. */ public boolean isSet(final int bitString) { return (bitString & getMask()) >> offset == 1; } /** * Computes the key usage value from one or more key usage bits. * * @param bits One ore more key usage bits. * * @return Key usage bit string as an integer. */ public static int usage(final KeyUsageBits... bits) { int usage = 0; for (KeyUsageBits bit : bits) { usage |= bit.getMask(); } return usage; } } cryptacular-1.2.5/src/main/java/org/cryptacular/x509/dn/000077500000000000000000000000001422604312300227275ustar00rootroot00000000000000cryptacular-1.2.5/src/main/java/org/cryptacular/x509/dn/Attribute.java000066400000000000000000000020701422604312300255340ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.x509.dn; /** * Simple implementation of the X.501 AttributeTypeAndValue that makes up the RelativeDistinguishedName type described * in section 4.1.2.4 of RFC 2459. * * @author Middleware Services */ public class Attribute { /** Attribute type. */ private final AttributeType type; /** Attribute value. */ private final String value; /** * Creates a new instance of the given type and value. * * @param type Attribute type. * @param value Attribute value. */ public Attribute(final AttributeType type, final String value) { if (type == null) { throw new IllegalArgumentException("Type cannot be null."); } this.type = type; if (value == null) { throw new IllegalArgumentException("Value cannot be null."); } this.value = value; } /** @return Attribute type. */ public AttributeType getType() { return type; } /** @return Attribute value. */ public String getValue() { return value; } } cryptacular-1.2.5/src/main/java/org/cryptacular/x509/dn/AttributeType.java000066400000000000000000000006301422604312300263760ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.x509.dn; /** * Describes values of AttributeType that may appear in a RelativeDistinguishedName (RDN) as defined in section 2 of RFC * 2253. * * @author Middleware Services */ public interface AttributeType { /** @return Attribute OID. */ String getOid(); /** @return Attribute name. */ String getName(); } cryptacular-1.2.5/src/main/java/org/cryptacular/x509/dn/Attributes.java000066400000000000000000000054501422604312300257240ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.x509.dn; import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.stream.Collectors; /** * Ordered list of {@link Attribute}s. * * @author Middleware Services */ public class Attributes implements Iterable { /** Underlying attributes. */ private final List attributes = new ArrayList<>(5); /** * Adds an attribute by type and value to the end of the attribute list. * * @param typeOid OID of attribute type. * @param value Attribute value. */ public void add(final String typeOid, final String value) { final StandardAttributeType type = StandardAttributeType.fromOid(typeOid); if (type != null) { add(new Attribute(type, value)); } else { add(new Attribute(new UnknownAttributeType(typeOid), value)); } } /** * Adds the given attribute to the end of the attribute list. * * @param attr Non-null attribute. */ public void add(final Attribute attr) { if (attr == null) { throw new IllegalArgumentException("Attribute cannot be null"); } attributes.add(attr); } /** * Gets the number of attributes contained in this instance. * * @return Number of attributes. */ public int size() { return attributes.size(); } /** * Gets an immutable list of attributes. * * @return Non-null immutable attribute list. */ public List getAll() { return Collections.unmodifiableList(attributes); } /** * Gets an immutable list of all attributes of the given type. The order of the returned list reflects the ordering of * the underlying attributes. * * @param type Attribute type. * * @return Non-null list of attributes of given type. An empty list is returned if there are no attributes of the * given type. */ public List getValues(final AttributeType type) { final List values = new ArrayList<>(attributes.size()); values.addAll( attributes.stream().filter( attr -> attr.getType().equals(type)).map(Attribute::getValue).collect(Collectors.toList())); return Collections.unmodifiableList(values); } /** * Gets the first value of the given type that appears in the attribute list. * * @param type Attribute type. * * @return Value of first attribute of given type or null if no attributes of given type exist. */ public String getValue(final AttributeType type) { for (Attribute attr : attributes) { if (attr.getType().equals(type)) { return attr.getValue(); } } return null; } @Override public Iterator iterator() { return attributes.iterator(); } } cryptacular-1.2.5/src/main/java/org/cryptacular/x509/dn/LdapNameFormatter.java000066400000000000000000000060441422604312300271430ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.x509.dn; import java.nio.ByteBuffer; import java.nio.CharBuffer; import java.nio.charset.StandardCharsets; import javax.security.auth.x500.X500Principal; import org.cryptacular.codec.HexEncoder; /** * Produces a string representation of an X.500 distinguished name using the process described in section 2 of RFC 2253, * LADPv3 Distinguished Names. * * @author Middleware Services */ public class LdapNameFormatter implements NameFormatter { /** Separator character between RDN components. */ public static final char RDN_SEPARATOR = ','; /** Separator character between ATV components in the same RDN element. */ public static final char ATV_SEPARATOR = '+'; /** Escape character. */ public static final char ESCAPE_CHAR = '\\'; /** String of characters that need to be escaped. */ public static final String RESERVED_CHARS = ",+\"\\<>;"; /** Handles hex encoding. */ private static final HexEncoder ENCODER = new HexEncoder(); @Override public String format(final X500Principal dn) { final StringBuilder builder = new StringBuilder(); final RDNSequence sequence = NameReader.readX500Principal(dn); int i = 0; for (RDN rdn : sequence.backward()) { if (i++ > 0) { builder.append(RDN_SEPARATOR); } int j = 0; for (Attribute attr : rdn.getAttributes()) { if (j++ > 0) { builder.append(ATV_SEPARATOR); } builder.append(attr.getType()).append('='); final AttributeType type = attr.getType(); if (type instanceof StandardAttributeType) { escape(attr.getValue(), builder); } else { encode(attr.getValue(), builder); } } } return builder.toString(); } /** * Appends the given value to the output with proper character escaping. * * @param value Value to escape. * @param output String builder where escaped value is written. */ private static void escape(final String value, final StringBuilder output) { char c = value.charAt(0); if (c == ' ' || c == '#') { output.append(ESCAPE_CHAR); } output.append(c); final int nmax = value.length() - 1; for (int n = 1; n < nmax; n++) { c = value.charAt(n); if (RESERVED_CHARS.indexOf(c) > -1) { output.append(ESCAPE_CHAR); } output.append(c); } c = value.charAt(nmax); if (c == ' ') { output.append(ESCAPE_CHAR); } output.append(c); } /** * Appends the given value to the output using the HEX encoding method described in section 2.4. * * @param value Value to encode. * @param output String builder where encoded value is written. */ private static void encode(final String value, final StringBuilder output) { output.append('#'); final byte[] bytes = value.getBytes(StandardCharsets.UTF_8); final CharBuffer out = CharBuffer.allocate(bytes.length * 2); ENCODER.encode(ByteBuffer.wrap(bytes), out); output.append(out.flip()); } } cryptacular-1.2.5/src/main/java/org/cryptacular/x509/dn/NameFormatter.java000066400000000000000000000010421422604312300263330ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.x509.dn; import javax.security.auth.x500.X500Principal; /** * Strategy pattern interface for producing a string representation of an X.500 distinguished name. * * @author Middleware Services */ public interface NameFormatter { /** * Produces a string representation of the given X.500 principal. * * @param dn Distinguished name as as X.500 principal. * * @return String representation of DN. */ String format(X500Principal dn); } cryptacular-1.2.5/src/main/java/org/cryptacular/x509/dn/NameReader.java000066400000000000000000000041401422604312300255740ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.x509.dn; import java.security.cert.X509Certificate; import javax.security.auth.x500.X500Principal; import org.bouncycastle.asn1.x500.AttributeTypeAndValue; import org.bouncycastle.asn1.x500.X500Name; /** * Reads X.509 subject and issuer DNs as a raw sequence of attributes to facilitate precise handling of name parsing. * * @author Middleware Services */ public class NameReader { /** Certificate to read. */ private final X509Certificate certificate; /** * Creates a new instance to support reading subject and issuer information on the given certificate. * * @param cert Certificate to read. */ public NameReader(final X509Certificate cert) { if (cert == null) { throw new IllegalArgumentException("Certificate cannot be null."); } this.certificate = cert; } /** * Reads the subject field from the certificate. * * @return Subject DN as an RDN sequence. */ public RDNSequence readSubject() { return readX500Principal(certificate.getSubjectX500Principal()); } /** * Reads the issuer field from the certificate. * * @return Issuer DN as an RDN sequence. */ public RDNSequence readIssuer() { return readX500Principal(certificate.getIssuerX500Principal()); } /** * Converts the given X.500 principal to a list of relative distinguished names that contains the attributes * comprising the DN. * * @param principal Principal to convert. * * @return X500 principal as an RDN sequence. */ public static RDNSequence readX500Principal(final X500Principal principal) { final X500Name name = X500Name.getInstance(principal.getEncoded()); final RDNSequence sequence = new RDNSequence(); for (org.bouncycastle.asn1.x500.RDN rdn : name.getRDNs()) { final Attributes attributes = new Attributes(); for (AttributeTypeAndValue tv : rdn.getTypesAndValues()) { attributes.add(tv.getType().getId(), tv.getValue().toString()); } sequence.add(new RDN(attributes)); } return sequence; } } cryptacular-1.2.5/src/main/java/org/cryptacular/x509/dn/RDN.java000066400000000000000000000014031422604312300242130ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.x509.dn; /** * Simple implementation of the X.501 RelativeDistinguishedName type described in section 4.1.2.4 of RFC 2459. * * @author Middleware Services */ public class RDN { /** RDN attributes. */ private final Attributes attributes; /** * Creates a new instance with given attributes. * * @param attributes Container for one or more AttributeTypeAndValues. */ public RDN(final Attributes attributes) { if (attributes == null) { throw new IllegalArgumentException("Attributes cannot be null"); } this.attributes = attributes; } /** @return RDN attributes. */ public Attributes getAttributes() { return attributes; } } cryptacular-1.2.5/src/main/java/org/cryptacular/x509/dn/RDNSequence.java000066400000000000000000000060371422604312300257140ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.x509.dn; import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.ListIterator; /** * Simple implementation of the X.501 RDNSequence type described in section 4.1.2.4 of RFC 2459. * * @author Middleware Services */ public class RDNSequence implements Iterable { /** Maintains the list/sequence of RDNs. */ private final List rdns = new ArrayList<>(10); /** * Adds an RDN to the sequence. * * @param rdn RDN to add. */ public void add(final RDN rdn) { rdns.add(rdn); } @Override public Iterator iterator() { return rdns.iterator(); } /** @return Iterable that moves backward over the RDN sequence. */ public Iterable backward() { return () -> new Iterator() { /** List iterator. */ private final ListIterator it = rdns.listIterator(rdns.size()); @Override public boolean hasNext() { return it.hasPrevious(); } @Override public RDN next() { return it.previous(); } @Override public void remove() { throw new UnsupportedOperationException("Remove not supported"); } }; } /** * Gets an immutable list of all attributes of the given type. The order of the returned list reflects the ordering of * the RDNs and their attributes. * * @param type Attribute type. * * @return Non-null list of attributes of given type. An empty list is returned if there are no attributes of the * given type. */ public List getValues(final AttributeType type) { final List values = new ArrayList<>(rdns.size()); for (RDN rdn : rdns) { values.addAll(rdn.getAttributes().getValues(type)); } return Collections.unmodifiableList(values); } /** * Gets the first value of the given type that appears in the attribute list of any RDN in the sequence. * * @param type Attribute type. * * @return Value of first attribute of given type or null if no attributes of given type exist. */ public String getValue(final AttributeType type) { final List values = getValues(type); if (values.size() > 0) { return values.get(0); } return null; } /** * Creates a comma-separated list of TYPE=VALUE tokens from the attributes in the list in order. * * @return String representation that resembles an X.509 distinguished name, e.g. CN=foo, OU=Bar, dc=example, * dc=com. */ @Override public String toString() { final StringBuilder builder = new StringBuilder(); int i = 0; for (RDN rdn : this) { for (Attribute attr : rdn.getAttributes()) { if (i++ > 0) { builder.append(", "); } builder.append(attr.getType()).append('=').append(attr.getValue()); } } return builder.toString(); } } cryptacular-1.2.5/src/main/java/org/cryptacular/x509/dn/StandardAttributeType.java000066400000000000000000000113341422604312300300620ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.x509.dn; /** * Describes the registered values of AttributeType that may appear in a RelativeDistinguishedName (RDN) as defined in * section 2 of RFC 2253. * *

Enumeration values include attributes likely to appear in an X.509 RDN, which were obtained from the following * sources:

* *
    *
  • RFC 4519 Lightweight Directory Access Protocol (LDAP): Schema for User Applications
  • *
  • RFC 4524 COSINE LDAP/X.500 Schema
  • *
  • PKCS #9 v2.0: Selected Object Classes and Attribute Types
  • *
* * @author Middleware Services * @version $Revision: 2745 $ */ public enum StandardAttributeType implements AttributeType { /** CN - RFC 4519 section 2.3. */ CommonName("2.5.4.3", "CN"), /** C - RFC 4519 section 2.2. */ CountryName("2.5.4.6", "C"), /** DESCRIPTION - RFC 4519 section 2.5. */ Description("2.5.4.13", "DESCRIPTION"), /** DNQUALIFIER - RFC 4519 section 2.8. */ DnQualifier("2.5.4.46", "DNQUALIFIER"), /** DC - RFC 4519 section 2.4. */ DomainComponent("0.9.2342.19200300.100.1.25", "DC"), /** Email address - PKCS#9 v2.0 section B.3.5. */ EmailAddress("1.2.840.113549.1.9.1", "EMAILADDRESS"), /** GenerationQualifier - RFC 4519 section 2.11. */ GenerationQualifier("2.5.4.44", "GENERATIONQUALIFIER"), /** GIVENNAME - RFC 4519 section 2.12. */ GivenName("2.5.4.42", "GIVENNAME"), /** INITIALS - RFC 4519 section 2.14. */ Initials("2.5.4.43", "INITIALS"), /** L - RFC 4519 section 2.16. */ LocalityName("2.5.4.7", "L"), /** MAIL - RFC 4524 section 2.16. */ Mail("0.9.2342.19200300.100.1.3", "MAIL"), /** NAME - RFC 4519 section 2.18. */ Name("2.5.4.41", "NAME"), /** O - RFC 4519 section 2.19. */ OrganizationName("2.5.4.10", "O"), /** OU - RFC 4519 section 2.20. */ OrganizationalUnitName("2.5.4.11", "OU"), /** POSTALADDRESS - RFC 4519 section 2.23. */ PostalAddress("2.5.4.16", "POSTALADDRESS"), /** POSTALCODE - RFC 4519 section 2.24. */ PostalCode("2.5.4.17", "POSTALCODE"), /** POSTOFFICEBOX - RFC 4519 section 2.25. */ PostOfficeBox("2.5.4.18", "POSTOFFICEBOX"), /** SERIALNUMBER - RFC 4519 section 2.31. */ SerialNumber("2.5.4.5", "SERIALNUMBER"), /** ST - RFC 4519 section 2.33. */ StateOrProvinceName("2.5.4.8", "ST"), /** STREET - RFC 4519 section 2.34. */ StreetAddress("2.5.4.9", "STREET"), /** SN - RFC 4519 section 2.32. */ Surname("2.5.4.4", "SN"), /** TELEPHONENUMBER - RFC 4519 section 2.35. */ TelephoneNumber("2.5.4.20", "TELEPHONENUMBER"), /** TITLE - RFC 4519 section 2.38. */ Title("2.5.4.12", "TITLE"), /** UNIQUEIDENTIFIER - RFC 4524 section 2.24. */ UniqueIdentifier("0.9.2342.19200300.100.1.44", "UNIQUEIDENTIFIER"), /** UID - RFC 4519 section 2.39. */ UserId("0.9.2342.19200300.100.1.1", "UID"); /** OID of RDN attribute type. */ private final String oid; /** Display string of the type in an RDN. */ private final String name; /** * Creates a new type for the given OID. * * @param attributeTypeOid OID of attribute type. * @param shortName Registered short name for the attribute type. */ StandardAttributeType(final String attributeTypeOid, final String shortName) { oid = attributeTypeOid; name = shortName; } /** @return OID of attribute type. */ @Override public String getOid() { return oid; } /** @return Registered short name of attribute type. */ @Override public String getName() { return name; } /** @return Attribute name. */ @Override public String toString() { return name; } /** * Gets the attribute type whose OID is the given string. * * @param oid OID of attribute type to get. * * @return Attribute type whose OID matches given value or none if there is no standard attribute type matching the * given OID. */ public static StandardAttributeType fromOid(final String oid) { for (StandardAttributeType t : StandardAttributeType.values()) { if (t.getOid().equals(oid)) { return t; } } return null; } /** * Gets the attribute type whose name is the given string. * * @param name Name of attribute to get, where the name is the all-caps RFC/standard name that would be returned by * {@link #getName()} for the desired attribute. * * @return Attribute type whose {@link #getName()} property matches the given value or null if there is no standard * attribute with the given name. */ public static AttributeType fromName(final String name) { for (AttributeType t : StandardAttributeType.values()) { if (t.getName().equals(name)) { return t; } } return null; } } cryptacular-1.2.5/src/main/java/org/cryptacular/x509/dn/UnknownAttributeType.java000066400000000000000000000021311422604312300277540ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.x509.dn; import java.util.regex.Pattern; /** * Describes a non-standard AttributeType in dotted decimal form that may appear in a RelativeDistinguishedName (RDN) as * defined in section 2 of RFC 2253. * * @author Middleware Services */ public class UnknownAttributeType implements AttributeType { /** Dotted decimal OID pattern. */ private static final Pattern PATTERN = Pattern.compile("[0-9]+(.[0-9]+)*"); /** Attribute type OID. */ private final String oid; /** * Creates a new instance from the given oid. * * @param attributeTypeOid Attribute type OID. */ public UnknownAttributeType(final String attributeTypeOid) { if (!PATTERN.matcher(attributeTypeOid).matches()) { throw new IllegalArgumentException(attributeTypeOid + " is not an OID"); } this.oid = attributeTypeOid; } @Override public String getOid() { return oid; } @Override public String getName() { return oid; } @Override public String toString() { return oid; } } cryptacular-1.2.5/src/openssl/000077500000000000000000000000001422604312300163175ustar00rootroot00000000000000cryptacular-1.2.5/src/openssl/gen-test-cert.sh000077500000000000000000000003731422604312300213420ustar00rootroot00000000000000#!/bin/sh if [ $# -lt 1 ]; then echo "USAGE: `basename $0` path/to/cert/file" exit fi CSR=request.csr openssl req -config openssl.cnf -new -key test-key.pem -out $CSR openssl ca -config openssl.cnf -days 10000 -in request.csr -out $1 rm -f $CSR cryptacular-1.2.5/src/openssl/openssl.cnf000066400000000000000000000173551422604312300205050ustar00rootroot00000000000000# # OpenSSL example configuration file. # This is mostly being used for generation of certificate requests. # # This definition stops the following lines choking if HOME isn't # defined. HOME = . RANDFILE = $ENV::HOME/.rnd # Extra OBJECT IDENTIFIER info: #oid_file = $ENV::HOME/.oid oid_section = new_oids # To use this configuration file with the "-extfile" option of the # "openssl x509" utility, name here the section containing the # X.509v3 extensions to use: # extensions = # (Alternatively, use a configuration file that has only # X.509v3 extensions in its main [= default] section.) [ new_oids ] # We can add new OIDs in here for use by 'ca' and 'req'. # Add a simple OID like this: # testoid1=1.2.3.4 # Or use config file substitution like this: # testoid2=${testoid1}.5.6 #################################################################### [ ca ] default_ca = CA_default # The default ca section #################################################################### [ CA_default ] dir = ./testCA # Where everything is kept certs = $dir/certs # Where the issued certs are kept crl_dir = $dir/crl # Where the issued crl are kept database = $dir/index.txt # database index file. new_certs_dir = $dir/newcerts # default place for new certs. certificate = $dir/ca/cacert.pem # The CA certificate serial = $dir/serial # The current serial number crl = $dir/crl.pem # The current CRL private_key = $dir/ca/cakey.pem # The private key RANDFILE = $dir/private/.rand # private random number file x509_extensions = usr_cert # The extentions to add to the cert # Comment out the following two lines for the "traditional" # (and highly broken) format. name_opt = ca_default # Subject Name options cert_opt = ca_default # Certificate field options # Extension copying option: use with caution. # copy_extensions = copy # Extensions to add to a CRL. Note: Netscape communicator chokes on V2 CRLs # so this is commented out by default to leave a V1 CRL. # crl_extensions = crl_ext default_days = 10000 # how long to certify for default_crl_days= 30 # how long before next CRL default_md = sha256 # which md to use. preserve = no # keep passed DN ordering # A few difference way of specifying how similar the request should look # For type CA, the listed attributes must be the same, and the optional # and supplied fields are just that :-) policy = policy_match # For the CA policy [ policy_match ] countryName = match stateOrProvinceName = match organizationName = match organizationalUnitName = optional commonName = supplied emailAddress = optional # For the 'anything' policy # At this point in time, you must list all acceptable 'object' # types. [ policy_anything ] countryName = optional stateOrProvinceName = optional localityName = optional organizationName = optional organizationalUnitName = optional commonName = supplied emailAddress = optional #################################################################### [ req ] default_bits = 2048 default_keyfile = serverkey.pem distinguished_name = req_distinguished_name attributes = req_attributes x509_extensions = v3_ca # The extentions to add to the self signed cert # Passwords for private keys if not present they will be prompted for # input_password = secret # output_password = secret # This sets a mask for permitted string types. There are several options. # default: PrintableString, T61String, BMPString. # pkix : PrintableString, BMPString. # utf8only: only UTF8Strings. # nombstr : PrintableString, T61String (no BMPStrings or UTF8Strings). # MASK:XXXX a literal mask value. # WARNING: current versions of Netscape crash on BMPStrings or UTF8Strings # so use this option with caution! string_mask = nombstr # req_extensions = v3_req # The extensions to add to a certificate request [ req_distinguished_name ] 0.domainComponent = Domain Component 1 (eg, edu, com) 0.domainComponent_default = com 1.domainComponent = Domain Component 2 (eg, vt) 1.domainComponent_default = example countryName = Country Name (2 letter code) countryName_default = US countryName_min = 2 countryName_max = 2 stateOrProvinceName = State or Province Name (full name) stateOrProvinceName_default = New York localityName = Locality Name (eg, city) localityName_default = New York 0.organizationName = Organization Name (eg, company) 0.organizationName_default = Snake Oil Unlimited commonName = Common Name (eg, YOUR server DNS name eg. server.dept.vt.edu must be less than 64 charactors) commonName_max = 64 commonName_default = something.example.com #emailAddress = Email Address #emailAddress_max = 64 # SET-ex3 = SET extension number 3 [ req_attributes ] #challengePassword = A challenge password #challengePassword_min = 4 #challengePassword_max = 20 #unstructuredName = An optional company name [ usr_cert ] # These extensions are added when 'ca' signs a request. # This goes against PKIX guidelines but some CAs do it and some software # requires this to avoid interpreting an end user certificate as a CA. basicConstraints=CA:FALSE # Here are some examples of the usage of nsCertType. If it is omitted # the certificate can be used for anything *except* object signing. # This is OK for an SSL server. # nsCertType = server # For an object signing certificate this would be used. # nsCertType = objsign # For normal client use this is typical # nsCertType = client, email # and for everything including object signing: # nsCertType = client, email, objsign # This is typical in keyUsage for a client certificate. # keyUsage = nonRepudiation, digitalSignature, keyEncipherment # This will be displayed in Netscape's comment listbox. nsComment = "OpenSSL Generated Certificate" # PKIX recommendations harmless if included in all certificates. subjectKeyIdentifier=hash authorityKeyIdentifier=keyid,issuer:always # This stuff is for subjectAltName and issuerAltname. # Import the email address. # subjectAltName=email:copy # An alternative to produce certificates that aren't # deprecated according to PKIX. # subjectAltName=email:move # Copy subject details issuerAltName=DNS:snake-1.example.com, DNS:snake-2.example.com nsCaRevocationUrl=http://crl.example.com/ca-crl.pem #nsBaseUrl #nsRevocationUrl #nsRenewalUrl #nsCaPolicyUrl #nsSslServerName [ v3_req ] # Extensions to add to a certificate request basicConstraints = CA:FALSE keyUsage = nonRepudiation, digitalSignature, keyEncipherment [ v3_ca ] # Extensions for a typical CA # PKIX recommendation. subjectKeyIdentifier=hash authorityKeyIdentifier=keyid:always,issuer:always # This is what PKIX recommends but some broken software chokes on critical # extensions. #basicConstraints = critical,CA:true # So we do this instead. basicConstraints = CA:true # Key usage: this is typical for a CA certificate. However since it will # prevent it being used as an test self-signed certificate it is best # left out by default. # keyUsage = cRLSign, keyCertSign # Some might want this also # nsCertType = sslCA, emailCA # Include email address in subject alt name: another PKIX recommendation # subjectAltName=email:copy # Copy issuer details # issuerAltName=issuer:copy # DER hex encoding of an extension: beware experts only! # obj=DER:02:03 # Where 'obj' is a standard or added object # You can even override a supported extension: # basicConstraints= critical, DER:30:03:01:01:FF [ crl_ext ] # CRL extensions. # Only issuerAltName and authorityKeyIdentifier make any sense in a CRL. # issuerAltName=issuer:copy authorityKeyIdentifier=keyid:always,issuer:always cryptacular-1.2.5/src/openssl/test-key.pem000066400000000000000000000032171422604312300205720ustar00rootroot00000000000000-----BEGIN RSA PRIVATE KEY----- MIIEpAIBAAKCAQEA3J6aPv2Zr+PvkUCxb1BL03wE6zTL/Jkqbfz+dItiCpDQ0395 W/D2/nY67p8J5z47WKbdkH8W2E2FZB3PRH8D9Vd0hlXGw9J3Fgg/AIa4s44SHuub /rNXeAERviYHVAS+/PesQoxivhJsP50pX0P92AOot9WlcR/nYlo5TAvhDw4xSNg4 Ya5IviTy9DX9x9qqv6PSIkY1wvALOAB6tnHq/xCwFsaWZJ9VjP7LyaKaeZmOgQ6v DZKUwJtiflVKsQYfUvChsFTJHbKZS3QUgLsuY7Ik5McgP8Ks5LpZZ+xF/R4SfTy1 2qxkI6qPcoWyKcdh8/fQO1R61FNqYhOSkWYodQIDAQABAoIBAQCHd9Qa7bnbKUlH lcPeKB4HZFXY33iKSLqnAvx0L8op1raDx/iLHjFsGskhEQMRvULPstbGDWPHugI4 cZ1938hcdDEW88CzKZ76JmIZPqBXkNtLpT0KbrE8/NsaOVuymZ900dgynOVc9Q8H GMf4uVU7uTN2fneyOPbpi6E3MuwlQ1urgo02WSyOfkMALtPBOvM/qajLv1LvIKxf lp7JfOrewZokMNX8NUraiGJmOOZsidgd66HLaxqjCALk/7UWTBh9vjur4jPn+qOm zukQSpmvoFMjtaoNSQXL7qqYTFKoLqfNNUhq/Ok533JHWSQhOM37YmfmfCEChxIE Qdlc0SSZAoGBAPbBRxbOOY6/55Qq5/uuAlMPDMpYIA8nas7P1XQhPd9Ai7RSkN9S wATZkOvr/KT07c0maFpWddIAxbgv27GN9VTF0G+HULItRRQ2C8LK/BhhnEVokMyl U4mnc3NTQCY1zIbaYJ0i/PEREOyR69WzIDJKl446SAqEgaTyVF6RGCHPAoGBAOTi pk92VJuc1vqDaxFoCUw1sUZtyrTCTX/jXxyEQhO8gZfq3m8dTVzW+3AKDlwvFNfj WPbJh5H36eHzXJBOomn4yIz9OV/+XmhBux8XESZODfeVF+UFepTc1V4q0TsrBUIf luK7ZFtaGWmho3Hn5RA1h8e0Z6c+4nKZ5i0Z3/Z7AoGANPEA/J6gcMUxvXN7NF+A Nivbdap0rmupmdezl2fua3DgyH6SgKezdRbs5gFKwmWeg86CwycbvkPWKA90lmK7 yUVr1BH3OVNHJ+/0lAWTEvQWYDnwH0g1ZSpdNdgdwlT2ndRKuEwicuJTfD5OmBoH hWLFo4lTnZYSbr5jZarBv7cCgYA+i+Uwr8BdKdXhbUoz3n8z8TQ5b8VF8hbljMev 7kB0Tj4HuqoAKTy70w+wxT65WDBU8o6cGeRPMjUahrtTv/lIBjEfvg8QuV0pFlVB ILeSBSBx+K8n6YBe753q9r5ocdAlCqbb3KOHBy8Mm5wjg2AoNsic/SKaJGgTMxUg XALEwwKBgQCpMQMlKkJniqwjdxqYVfsHNmnTZVWBlu7I5Pph2Os2VGGW+w10XWcX h0P3ys6abPQQjzh7STbXGnFYJH1oK1X98jahjI5iMwwpI+4KfcRThbn9nC8qftVL ZvD1krEMJbkvke7PnUX/idBmI7VNXhq4538WL47w29jmnmkYNQQFTA== -----END RSA PRIVATE KEY----- cryptacular-1.2.5/src/openssl/testCA/000077500000000000000000000000001422604312300175025ustar00rootroot00000000000000cryptacular-1.2.5/src/openssl/testCA/ca/000077500000000000000000000000001422604312300200655ustar00rootroot00000000000000cryptacular-1.2.5/src/openssl/testCA/ca/cacert.pem000066400000000000000000000032501422604312300220310ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIEvTCCA6WgAwIBAgIJALk9c4BcQN5DMA0GCSqGSIb3DQEBBQUAMIGaMRMwEQYK CZImiZPyLGQBGRYDY29tMRcwFQYKCZImiZPyLGQBGRYHZXhhbXBsZTELMAkGA1UE BhMCVVMxETAPBgNVBAgTCE5ldyBZb3JrMREwDwYDVQQHEwhOZXcgWW9yazEcMBoG A1UEChMTU25ha2UgT2lsIFVubGltaXRlZDEZMBcGA1UEAxMQcm9vdC5leGFtcGxl LmNvbTAeFw0xMzEyMDQxNjM3MjBaFw00MTA0MjExNjM3MjBaMIGaMRMwEQYKCZIm iZPyLGQBGRYDY29tMRcwFQYKCZImiZPyLGQBGRYHZXhhbXBsZTELMAkGA1UEBhMC VVMxETAPBgNVBAgTCE5ldyBZb3JrMREwDwYDVQQHEwhOZXcgWW9yazEcMBoGA1UE ChMTU25ha2UgT2lsIFVubGltaXRlZDEZMBcGA1UEAxMQcm9vdC5leGFtcGxlLmNv bTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANhHTFSyNtSs3AwtbvUe x3DNySOxmIXU3C5HUBNLRvRvW5uVhXg6xUd/vJkuy6vNIkXJUVqgft+NHI3OmyNX W0ElD4d5wK24/HuuA7iUkOtRQ2oqxrdQQQ+u12y1yLOE/+Dbt0wMaxxdU8LL/VEu oj3eRRoaWJsWLsctR/Y3b6nddhG1pAeB/S1x0BGq+k8EB09ijYQ6Lmxi4WaPnZqy vHXgbBgCT5K7pY0AxMy2Nctam71O+2D8W3m5DSx9eEPpxhqXBfp+fM/HYeG7lMX7 sURD+6CZ5RaoHCdGFVh3TWzjs32WjV047QdwRQGzcJ6GIxfXjBjMECLwqKAyMMpb Bf0CAwEAAaOCAQIwgf8wHQYDVR0OBBYEFH1agQiTu1LPLGbN18FHsxFLAUNsMIHP BgNVHSMEgccwgcSAFH1agQiTu1LPLGbN18FHsxFLAUNsoYGgpIGdMIGaMRMwEQYK CZImiZPyLGQBGRYDY29tMRcwFQYKCZImiZPyLGQBGRYHZXhhbXBsZTELMAkGA1UE BhMCVVMxETAPBgNVBAgTCE5ldyBZb3JrMREwDwYDVQQHEwhOZXcgWW9yazEcMBoG A1UEChMTU25ha2UgT2lsIFVubGltaXRlZDEZMBcGA1UEAxMQcm9vdC5leGFtcGxl LmNvbYIJALk9c4BcQN5DMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEB AHtnPxtwM5wOu1utXlnwzTOepeM10OVIOIrJRNfGaz9cwxMEvlFp5PdhNBdlV460 loAe9NtWDz6IieWJJXNx+h+CeMwOG9jnSYtCKpd2dfICyNypD3PUtHwyx81mxExz /fK87G6Wfo53j4kuUBL+wzI2qQfaPZ95oDpLySQ/i/l6nzD2+lDczYUCaynwPcRq MzMLyvpt6Km3gAZHXKB8VNtR+Sr655oMysOB0jcHetMnVvKm87ByZP/ErnCMWQZy rEZClf93OaTQCcMcOJSrnVWOgi0o31m90MQjRwdh09ZtikuRSutkA4xrU3rPOgmV c/9bYt2L/wzfV1v3JaBJEQs= -----END CERTIFICATE----- cryptacular-1.2.5/src/openssl/testCA/ca/cakey.pem000066400000000000000000000032131422604312300216630ustar00rootroot00000000000000-----BEGIN RSA PRIVATE KEY----- MIIEogIBAAKCAQEA2EdMVLI21KzcDC1u9R7HcM3JI7GYhdTcLkdQE0tG9G9bm5WF eDrFR3+8mS7Lq80iRclRWqB+340cjc6bI1dbQSUPh3nArbj8e64DuJSQ61FDairG t1BBD67XbLXIs4T/4Nu3TAxrHF1Twsv9US6iPd5FGhpYmxYuxy1H9jdvqd12EbWk B4H9LXHQEar6TwQHT2KNhDoubGLhZo+dmrK8deBsGAJPkruljQDEzLY1y1qbvU77 YPxbebkNLH14Q+nGGpcF+n58z8dh4buUxfuxREP7oJnlFqgcJ0YVWHdNbOOzfZaN XTjtB3BFAbNwnoYjF9eMGMwQIvCooDIwylsF/QIDAQABAoIBAEsVdYpx1FdBK6OO ola2uMaQqqOZpDnSDB6E42fPWnLBtivtXMjAnnyT/AWyGUMrlBpmKbgsv98cPi18 7J74VNXo59tAiYPGFOFbKC+MZENNkvnon9REKFIpgOBcu7CXG74UiS39obHXNJ0L 9IWaivivkY3eV6R/rv222qS/2iQ9+p8Y3vqCGIzRtPCfNq3mPK9/nzyKPnwq3sJX tq6hJuBaKuoJV6omCZG8FWK4EZXUVAaUXWXeCoA+cWuz1gmXe9mY4Xh1JOCfwzTh wVkWcg7CqSgjsBvrq8twVU47EF68Rqo6g/ntGuyb4Qe6UPjlDEliakYV+os8hNbs p6DLUAECgYEA9JUKXnHHUkSqQCsYLcr3h0PZ93///jomyc/t8vtdbE5f0T6e46d+ KFoVsdJ6H9rFd2TGh+FythQ91Mbz0YQeEdIEK+dS9IVjBgXKaAgQC0XW3VtMWYa5 hWoTNEy0y4eYxCuRDfIIkteiJwwabLLeLA0MFRKSol89Wd5D7M6dI90CgYEA4mAB WM9TeiJF7AyDO/xXogF+VrCWayxeWsUvm228xG+AemWVFxYc3LTVwC2SRU+SJpA/ UKM8DMB5lNEip9u6XDzRjqDHG08FQshxdvizttugsn4MGiYfeDv7bAs3Lm6xIUuG 9UmC7j2XPCnbtTZMz/5jL/9hY08ki2NmLjqJ2KECgYABwBNL67qGbzFctjI9Gae9 0xF7QPI/CoF+jjtgssXPYZwz7iPK80bm2QYwuJXhJnqlSRZWoJlmjiyHGkliZXSl ogAfpE8mqtGzmFUDe5NJ0V0hRmb8eQdY2hJ7HFVq43SHatxl4iaHjn19lAuYXYtT e2Brwi9EdDQHMZ0A09WyDQKBgDCVLBTUQfUXP+xd7xhDmscRDP0r3sxXdFSEtyfj UDzUNT2PaYTP4RfY03rwDNFFN3eBQ6VZsvyFnlI64/YkaQV8o/i5NqH8voNLo1ZG H8OhtQY5mP1PqzdRoC7a5VfYt7kOjYM86JWasEdgMF/erHODA+R8KXl3tb8YcQiA 1a6hAoGAdYwuHLeH+Nwr2q5+m3QEkCmfuAMo3oWCGccdOetrCUVViRuOM6IR8L4s 46bG8cbnOQ90SWqyIwLH8RPEkMykcRpLw/1XGG5tmpXgvPgNSwPsZj2a33yJBAW1 JtGXcSMQPfzROahNKBFlV9qcF+3FL0mf3B/y24rEyRKFuIiAvhQ= -----END RSA PRIVATE KEY----- cryptacular-1.2.5/src/openssl/testCA/index.txt000066400000000000000000000001301422604312300213440ustar00rootroot00000000000000V 410421165056Z 01 unknown /C=US/ST=New York/O=Snake Oil Unlimited/CN=test.example.com cryptacular-1.2.5/src/openssl/testCA/index.txt.attr000066400000000000000000000000251422604312300223200ustar00rootroot00000000000000unique_subject = yes cryptacular-1.2.5/src/openssl/testCA/index.txt.old000066400000000000000000000000001422604312300221150ustar00rootroot00000000000000cryptacular-1.2.5/src/openssl/testCA/newcerts/000077500000000000000000000000001422604312300213345ustar00rootroot00000000000000cryptacular-1.2.5/src/openssl/testCA/newcerts/01.pem000066400000000000000000000123001422604312300222530ustar00rootroot00000000000000Certificate: Data: Version: 3 (0x2) Serial Number: 1 (0x1) Signature Algorithm: sha256WithRSAEncryption Issuer: DC=com, DC=example, C=US, ST=New York, L=New York, O=Snake Oil Unlimited, CN=root.example.com Validity Not Before: Dec 4 16:50:56 2013 GMT Not After : Apr 21 16:50:56 2041 GMT Subject: C=US, ST=New York, O=Snake Oil Unlimited, CN=test.example.com Subject Public Key Info: Public Key Algorithm: rsaEncryption RSA Public Key: (2048 bit) Modulus (2048 bit): 00:dc:9e:9a:3e:fd:99:af:e3:ef:91:40:b1:6f:50: 4b:d3:7c:04:eb:34:cb:fc:99:2a:6d:fc:fe:74:8b: 62:0a:90:d0:d3:7f:79:5b:f0:f6:fe:76:3a:ee:9f: 09:e7:3e:3b:58:a6:dd:90:7f:16:d8:4d:85:64:1d: cf:44:7f:03:f5:57:74:86:55:c6:c3:d2:77:16:08: 3f:00:86:b8:b3:8e:12:1e:eb:9b:fe:b3:57:78:01: 11:be:26:07:54:04:be:fc:f7:ac:42:8c:62:be:12: 6c:3f:9d:29:5f:43:fd:d8:03:a8:b7:d5:a5:71:1f: e7:62:5a:39:4c:0b:e1:0f:0e:31:48:d8:38:61:ae: 48:be:24:f2:f4:35:fd:c7:da:aa:bf:a3:d2:22:46: 35:c2:f0:0b:38:00:7a:b6:71:ea:ff:10:b0:16:c6: 96:64:9f:55:8c:fe:cb:c9:a2:9a:79:99:8e:81:0e: af:0d:92:94:c0:9b:62:7e:55:4a:b1:06:1f:52:f0: a1:b0:54:c9:1d:b2:99:4b:74:14:80:bb:2e:63:b2: 24:e4:c7:20:3f:c2:ac:e4:ba:59:67:ec:45:fd:1e: 12:7d:3c:b5:da:ac:64:23:aa:8f:72:85:b2:29:c7: 61:f3:f7:d0:3b:54:7a:d4:53:6a:62:13:92:91:66: 28:75 Exponent: 65537 (0x10001) X509v3 extensions: X509v3 Basic Constraints: CA:FALSE Netscape Comment: OpenSSL Generated Certificate X509v3 Subject Key Identifier: 44:88:EF:79:2B:51:0B:16:31:FE:62:C3:2E:D3:26:F6:A8:EF:CD:A3 X509v3 Authority Key Identifier: keyid:7D:5A:81:08:93:BB:52:CF:2C:66:CD:D7:C1:47:B3:11:4B:01:43:6C DirName:/DC=com/DC=example/C=US/ST=New York/L=New York/O=Snake Oil Unlimited/CN=root.example.com serial:B9:3D:73:80:5C:40:DE:43 X509v3 Issuer Alternative Name: DNS:snake-1.example.com, DNS:snake-2.example.com Netscape CA Revocation Url: http://crl.example.com/ca-crl.pem Signature Algorithm: sha256WithRSAEncryption a3:f0:4a:d0:e6:2a:b2:f2:ab:4e:68:05:89:9d:d4:95:cc:7d: 7c:01:39:44:f0:9a:52:18:3c:49:78:3b:1b:95:00:7a:25:f0: c7:e6:25:a0:41:20:5f:86:8d:e3:c5:59:79:fe:6d:99:81:23: 40:a7:52:ed:b8:18:dd:f8:37:b9:5b:99:39:c2:6f:0f:8f:4a: 5f:c3:dd:b4:fd:ca:be:a2:5d:f5:56:8a:d6:f2:cd:ce:e7:92: 01:0f:4c:9c:a8:63:5a:2a:53:ca:ce:fe:88:87:f1:76:7e:6f: 0d:d0:55:b3:c2:db:03:13:f2:ea:88:0a:1b:a7:0e:cf:54:a9: 02:63:fc:1a:0f:94:40:68:46:f5:e2:4a:77:d1:fa:a7:35:d3: 0e:ba:17:1c:55:08:ca:e4:30:39:0f:c9:39:0b:e6:a7:f9:f9: 25:2f:8e:0f:88:81:5c:16:04:e0:0f:69:9b:21:87:4f:92:dd: ed:37:f6:a6:01:5d:7d:af:1d:fb:9f:53:67:2f:d2:8c:10:dd: d7:fb:16:ea:18:7f:47:28:d0:91:d7:1e:d7:25:a0:ed:0b:8c: 29:94:d5:a8:43:e8:74:f4:bf:f6:bd:d4:78:fe:c5:bd:5a:87: 53:27:ad:70:2c:77:61:4c:98:50:c9:c6:db:c8:d6:74:0e:1b: a9:04:2a:db -----BEGIN CERTIFICATE----- MIIFBjCCA+6gAwIBAgIBATANBgkqhkiG9w0BAQsFADCBmjETMBEGCgmSJomT8ixk ARkWA2NvbTEXMBUGCgmSJomT8ixkARkWB2V4YW1wbGUxCzAJBgNVBAYTAlVTMREw DwYDVQQIEwhOZXcgWW9yazERMA8GA1UEBxMITmV3IFlvcmsxHDAaBgNVBAoTE1Nu YWtlIE9pbCBVbmxpbWl0ZWQxGTAXBgNVBAMTEHJvb3QuZXhhbXBsZS5jb20wHhcN MTMxMjA0MTY1MDU2WhcNNDEwNDIxMTY1MDU2WjBZMQswCQYDVQQGEwJVUzERMA8G A1UECBMITmV3IFlvcmsxHDAaBgNVBAoTE1NuYWtlIE9pbCBVbmxpbWl0ZWQxGTAX BgNVBAMTEHRlc3QuZXhhbXBsZS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw ggEKAoIBAQDcnpo+/Zmv4++RQLFvUEvTfATrNMv8mSpt/P50i2IKkNDTf3lb8Pb+ djrunwnnPjtYpt2QfxbYTYVkHc9EfwP1V3SGVcbD0ncWCD8AhrizjhIe65v+s1d4 ARG+JgdUBL7896xCjGK+Emw/nSlfQ/3YA6i31aVxH+diWjlMC+EPDjFI2Dhhrki+ JPL0Nf3H2qq/o9IiRjXC8As4AHq2cer/ELAWxpZkn1WM/svJopp5mY6BDq8NkpTA m2J+VUqxBh9S8KGwVMkdsplLdBSAuy5jsiTkxyA/wqzkulln7EX9HhJ9PLXarGQj qo9yhbIpx2Hz99A7VHrUU2piE5KRZih1AgMBAAGjggGVMIIBkTAJBgNVHRMEAjAA MCwGCWCGSAGG+EIBDQQfFh1PcGVuU1NMIEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTAd BgNVHQ4EFgQURIjveStRCxYx/mLDLtMm9qjvzaMwgc8GA1UdIwSBxzCBxIAUfVqB CJO7Us8sZs3XwUezEUsBQ2yhgaCkgZ0wgZoxEzARBgoJkiaJk/IsZAEZFgNjb20x FzAVBgoJkiaJk/IsZAEZFgdleGFtcGxlMQswCQYDVQQGEwJVUzERMA8GA1UECBMI TmV3IFlvcmsxETAPBgNVBAcTCE5ldyBZb3JrMRwwGgYDVQQKExNTbmFrZSBPaWwg VW5saW1pdGVkMRkwFwYDVQQDExByb290LmV4YW1wbGUuY29tggkAuT1zgFxA3kMw MwYDVR0SBCwwKoITc25ha2UtMS5leGFtcGxlLmNvbYITc25ha2UtMi5leGFtcGxl LmNvbTAwBglghkgBhvhCAQQEIxYhaHR0cDovL2NybC5leGFtcGxlLmNvbS9jYS1j cmwucGVtMA0GCSqGSIb3DQEBCwUAA4IBAQCj8ErQ5iqy8qtOaAWJndSVzH18ATlE 8JpSGDxJeDsblQB6JfDH5iWgQSBfho3jxVl5/m2ZgSNAp1LtuBjd+De5W5k5wm8P j0pfw920/cq+ol31VorW8s3O55IBD0ycqGNaKlPKzv6Ih/F2fm8N0FWzwtsDE/Lq iAobpw7PVKkCY/waD5RAaEb14kp30fqnNdMOuhccVQjK5DA5D8k5C+an+fklL44P iIFcFgTgD2mbIYdPkt3tN/amAV19rx37n1NnL9KMEN3X+xbqGH9HKNCR1x7XJaDt C4wplNWoQ+h09L/2vdR4/sW9WodTJ61wLHdhTJhQycbbyNZ0DhupBCrb -----END CERTIFICATE----- cryptacular-1.2.5/src/openssl/testCA/serial000066400000000000000000000000031422604312300206750ustar00rootroot0000000000000002 cryptacular-1.2.5/src/openssl/testCA/serial.old000066400000000000000000000000031422604312300214520ustar00rootroot0000000000000001 cryptacular-1.2.5/src/test/000077500000000000000000000000001422604312300156135ustar00rootroot00000000000000cryptacular-1.2.5/src/test/java/000077500000000000000000000000001422604312300165345ustar00rootroot00000000000000cryptacular-1.2.5/src/test/java/org/000077500000000000000000000000001422604312300173235ustar00rootroot00000000000000cryptacular-1.2.5/src/test/java/org/cryptacular/000077500000000000000000000000001422604312300216545ustar00rootroot00000000000000cryptacular-1.2.5/src/test/java/org/cryptacular/CiphertextHeaderTest.java000066400000000000000000000033761422604312300266200ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular; import java.util.Arrays; import org.cryptacular.util.CodecUtil; import org.testng.annotations.Test; import static org.testng.Assert.assertEquals; /** * Unit test for {@link CiphertextHeader}. * * @author Middleware Services */ public class CiphertextHeaderTest { @Test( expectedExceptions = IllegalArgumentException.class, expectedExceptionsMessageRegExp = "Nonce exceeds size limit in bytes.*") public void testNonceLimitConstructor() { new CiphertextHeader(new byte[256], "key2"); } @Test public void testEncodeDecodeSuccess() { final byte[] nonce = new byte[255]; Arrays.fill(nonce, (byte) 7); final CiphertextHeader expected = new CiphertextHeader(nonce, "aleph"); final byte[] encoded = expected.encode(); assertEquals(expected.getLength(), encoded.length); final CiphertextHeader actual = CiphertextHeader.decode(encoded); assertEquals(expected.getNonce(), actual.getNonce()); assertEquals(expected.getKeyName(), actual.getKeyName()); assertEquals(expected.getLength(), actual.getLength()); } @Test( expectedExceptions = EncodingException.class, expectedExceptionsMessageRegExp = "Bad ciphertext header: maximum nonce length exceeded") public void testDecodeFailNonceLengthExceeded() { // https://github.com/vt-middleware/cryptacular/issues/52 CiphertextHeader.decode(CodecUtil.hex("000000347ffffffd")); } @Test( expectedExceptions = EncodingException.class, expectedExceptionsMessageRegExp = "Bad ciphertext header: maximum key length exceeded") public void testDecodeFailKeyLengthExceeded() { CiphertextHeader.decode(CodecUtil.hex("000000F300000004DEADBEEF00FFFFFF")); } } cryptacular-1.2.5/src/test/java/org/cryptacular/CiphertextHeaderV2Test.java000066400000000000000000000041531422604312300270220ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular; import java.util.Arrays; import javax.crypto.SecretKey; import javax.crypto.spec.SecretKeySpec; import org.cryptacular.generator.sp80038a.RBGNonce; import org.testng.annotations.Test; import static org.testng.Assert.assertEquals; /** * Unit test for {@link CiphertextHeaderV2}. * * @author Middleware Services */ public class CiphertextHeaderV2Test { /** Test HMAC key. */ private final SecretKey key = new SecretKeySpec(new RBGNonce().generate(), "AES"); @Test( expectedExceptions = IllegalArgumentException.class, expectedExceptionsMessageRegExp = "Nonce exceeds size limit in bytes.*") public void testNonceLimitConstructor() { new CiphertextHeaderV2(new byte[256], "key2"); } @Test public void testEncodeDecodeSuccess() { final byte[] nonce = new byte[255]; Arrays.fill(nonce, (byte) 7); final CiphertextHeaderV2 expected = new CiphertextHeaderV2(nonce, "aleph"); expected.setKeyLookup(this::getKey); final byte[] encoded = expected.encode(); assertEquals(expected.getLength(), encoded.length); final CiphertextHeaderV2 actual = CiphertextHeaderV2.decode(encoded, this::getKey); assertEquals(expected.getNonce(), actual.getNonce()); assertEquals(expected.getKeyName(), actual.getKeyName()); assertEquals(expected.getLength(), actual.getLength()); } @Test( expectedExceptions = EncodingException.class, expectedExceptionsMessageRegExp = "Ciphertext header HMAC verification failed") public void testEncodeDecodeFailBadHMAC() { final byte[] nonce = new byte[16]; Arrays.fill(nonce, (byte) 3); final CiphertextHeaderV2 expected = new CiphertextHeaderV2(nonce, "aleph"); // Tamper with computed HMAC final byte[] encoded = expected.encode(key); final int index = encoded.length - 3; final byte b = encoded[index]; encoded[index] = (byte) (b + 1); CiphertextHeaderV2.decode(encoded, this::getKey); } private SecretKey getKey(final String alias) { if ("aleph".equals(alias)) { return key; } return null; } } cryptacular-1.2.5/src/test/java/org/cryptacular/FailListener.java000066400000000000000000000011371422604312300251020ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular; import org.testng.ITestResult; import org.testng.TestListenerAdapter; /** * TestNG listener that converts skipped results to failures when the cause of skip is an error. * A common use case for this listener is triggering failures on @DataProvider errors. * * @author Middleware Services */ public class FailListener extends TestListenerAdapter { @Override public void onTestSkipped(final ITestResult tr) { if (tr.getThrowable() != null) { tr.setStatus(ITestResult.FAILURE); } } } cryptacular-1.2.5/src/test/java/org/cryptacular/adapter/000077500000000000000000000000001422604312300232745ustar00rootroot00000000000000cryptacular-1.2.5/src/test/java/org/cryptacular/adapter/WrappedKeyTest.java000066400000000000000000000057061422604312300270620ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.adapter; import java.io.FileOutputStream; import java.io.IOException; import java.security.KeyFactory; import java.security.KeyPair; import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.X509EncodedKeySpec; import org.cryptacular.FailListener; import org.cryptacular.util.KeyPairUtil; import org.cryptacular.util.StreamUtil; import org.testng.annotations.DataProvider; import org.testng.annotations.Listeners; import org.testng.annotations.Test; import static org.testng.AssertJUnit.assertTrue; /** * Test for {@link AbstractWrappedKey} classes. * * @author Middleware Services */ @Listeners(FailListener.class) public class WrappedKeyTest { private static final String KEY_PATH = "src/test/resources/keys/"; @DataProvider(name = "keypairs") public Object[][] getKeyPairs() { return new Object[][] { {"DSA", KEY_PATH + "dsa-pub.der", KEY_PATH + "dsa-pkcs8-nopass.der", }, {"RSA", KEY_PATH + "rsa-pub.der", KEY_PATH + "rsa-pkcs8-nopass.der", }, // TODO: enable once BC gets support for writing EC named curves // As of bcprov 1.50 only raw EC params can be written // SunJCE only understands named curves // { // "EC", // KEY_PATH + "ec-prime256v1-named-pub.der", // KEY_PATH + "ec-pkcs8-prime256v1-named-nopass.der", // }, }; } @Test(dataProvider = "keypairs") public void testKeyEquivalence(final String algorithm, final String pubKeyPath, final String privKeyPath) throws Exception { final KeyPair wrappedPair = new KeyPair( KeyPairUtil.readPublicKey(pubKeyPath), KeyPairUtil.readPrivateKey(privKeyPath)); final String bcPubKeyPath = String.format("target/%s-%s.key", algorithm, "pub"); final String bcPrivKeyPath = String.format("target/%s-%s.key", algorithm, "priv"); writeFile(bcPubKeyPath, wrappedPair.getPublic().getEncoded()); writeFile(bcPrivKeyPath, wrappedPair.getPrivate().getEncoded()); final KeyPair jcePair = readJCEKeyPair(algorithm, bcPubKeyPath, bcPrivKeyPath); assertTrue(KeyPairUtil.isKeyPair(wrappedPair.getPublic(), jcePair.getPrivate())); assertTrue(KeyPairUtil.isKeyPair(jcePair.getPublic(), wrappedPair.getPrivate())); } private static void writeFile(final String path, final byte[] data) throws IOException { try (FileOutputStream out = new FileOutputStream(path)) { out.write(data); } } private static KeyPair readJCEKeyPair(final String algorithm, final String pubKeyPath, final String privKeyPath) throws Exception { final PKCS8EncodedKeySpec privSpec = new PKCS8EncodedKeySpec(StreamUtil.readAll(privKeyPath)); final X509EncodedKeySpec pubSpec = new X509EncodedKeySpec(StreamUtil.readAll(pubKeyPath)); final KeyFactory factory = KeyFactory.getInstance(algorithm); return new KeyPair(factory.generatePublic(pubSpec), factory.generatePrivate(privSpec)); } } cryptacular-1.2.5/src/test/java/org/cryptacular/bean/000077500000000000000000000000001422604312300225615ustar00rootroot00000000000000cryptacular-1.2.5/src/test/java/org/cryptacular/bean/AEADBlockCipherBeanTest.java000066400000000000000000000122351422604312300276550ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.bean; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.security.KeyStore; import org.cryptacular.FailListener; import org.cryptacular.generator.sp80038d.CounterNonce; import org.cryptacular.io.FileResource; import org.cryptacular.spec.AEADBlockCipherSpec; import org.cryptacular.util.ByteUtil; import org.cryptacular.util.CodecUtil; import org.cryptacular.util.StreamUtil; import org.testng.annotations.DataProvider; import org.testng.annotations.Listeners; import org.testng.annotations.Test; import static org.testng.Assert.assertEquals; /** * Unit test for {@link AEADBlockCipherBean}. * * @author Middleware Services */ @Listeners(FailListener.class) public class AEADBlockCipherBeanTest { @DataProvider(name = "test-arrays") public Object[][] getTestArrays() { return new Object[][] { new Object[] { // Plaintext is NOT multiple of block size "Able was I ere I saw elba.", "AES/GCM", }, // Plaintext is multiple of block size new Object[] { "Four score and seven years ago, our forefathers ", "Twofish/CCM", }, // OCB new Object[] { "Have you passed through this night?", "Twofish/OCB", }, // EAX new Object[] { "I went to the woods because I wished to live deliberately, to front only the essential facts of life", "AES/EAX", }, }; } @DataProvider(name = "test-streams") public Object[][] getTestStreams() { return new Object[][] { new Object[] { "src/test/resources/plaintexts/lorem-5000.txt", "Twofish/GCM", }, new Object[] { "src/test/resources/plaintexts/lorem-1200.txt", "AES/OCB", }, new Object[] { "src/test/resources/plaintexts/lorem-1200.txt", "AES/EAX", }, }; } @Test(dataProvider = "test-arrays") public void testEncryptDecryptArray(final String input, final String cipherSpecString) throws Exception { final AEADBlockCipherBean cipherBean = newCipherBean(AEADBlockCipherSpec.parse(cipherSpecString)); final byte[] ciphertext = cipherBean.encrypt(ByteUtil.toBytes(input)); assertEquals(ByteUtil.toString(cipherBean.decrypt(ciphertext)), input); } @Test(dataProvider = "test-streams") public void testEncryptDecryptStream(final String path, final String cipherSpecString) throws Exception { final AEADBlockCipherBean cipherBean = newCipherBean(AEADBlockCipherSpec.parse(cipherSpecString)); final ByteArrayOutputStream tempOut = new ByteArrayOutputStream(8192); cipherBean.encrypt(StreamUtil.makeStream(new File(path)), tempOut); final ByteArrayInputStream tempIn = new ByteArrayInputStream(tempOut.toByteArray()); final ByteArrayOutputStream finalOut = new ByteArrayOutputStream(8192); cipherBean.decrypt(tempIn, finalOut); assertEquals(ByteUtil.toString(finalOut.toByteArray()), ByteUtil.toString(StreamUtil.readAll(path))); } @Test public void testDecryptArrayBackwardCompatibleHeader() { final AEADBlockCipherBean cipherBean = newCipherBean(new AEADBlockCipherSpec("Twofish", "OCB")); final String expected = "Have you passed through this night?"; final String v1CiphertextHex = "0000001f0000000c76746d770002ba17043672d900000007767463727970745a38dee735266e3f5f7aafec8d1c9ed8a0830a2ff9" + "c3a46c25f89e69b6eb39dbb82fd13da50e32b2544a73f1a4476677b377e6"; final byte[] plaintext = cipherBean.decrypt(CodecUtil.hex(v1CiphertextHex)); assertEquals(expected, ByteUtil.toString(plaintext)); } @Test public void testDecryptStreamBackwardCompatibleHeader() { final AEADBlockCipherBean cipherBean = newCipherBean(new AEADBlockCipherSpec("Twofish", "OCB")); final String expected = "Have you passed through this night?"; final String v1CiphertextHex = "0000001f0000000c76746d770002ba17043672d900000007767463727970745a38dee735266e3f5f7aafec8d1c9ed8a0830a2ff9" + "c3a46c25f89e69b6eb39dbb82fd13da50e32b2544a73f1a4476677b377e6"; final ByteArrayInputStream in = new ByteArrayInputStream(CodecUtil.hex(v1CiphertextHex)); final ByteArrayOutputStream out = new ByteArrayOutputStream(); cipherBean.decrypt(in, out); assertEquals(expected, ByteUtil.toString(out.toByteArray())); } private static KeyStore getTestKeyStore() { final KeyStoreFactoryBean bean = new KeyStoreFactoryBean(); bean.setPassword("vtcrypt"); bean.setResource(new FileResource(new File("src/test/resources/keystores/cipher-bean.jceks"))); bean.setType("JCEKS"); return bean.newInstance(); } private static AEADBlockCipherBean newCipherBean(final AEADBlockCipherSpec cipherSpec) { final AEADBlockCipherBean cipherBean = new AEADBlockCipherBean(); cipherBean.setNonce(new CounterNonce("vtmw", System.nanoTime())); cipherBean.setKeyAlias("vtcrypt"); cipherBean.setKeyPassword("vtcrypt"); cipherBean.setKeyStore(getTestKeyStore()); cipherBean.setBlockCipherSpec(cipherSpec); return cipherBean; } } cryptacular-1.2.5/src/test/java/org/cryptacular/bean/BCryptHashBeanTest.java000066400000000000000000000026001422604312300270570ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.bean; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertTrue; /** * Unit test for {@link BCryptHashBean} class. * * @author Middleware Services */ public class BCryptHashBeanTest { @DataProvider(name = "hashes") public Object[][] getHashData() { return new Object[][] { {"password", "$2a$5$bvIG6Nmid91Mu9RcmmWZfO5HJIMCT8riNW0hEp8f6/FuA2/mHZFpe"}, {"x", "$2a$12$w6IdiZTAckGirKaH8LU8VOxEvP97cFLEW5ePVJzhZilSa5c.V/uMK"}, {"abcdefghijklmnopqrstuvwxyz", "$2a$6$.rCVZVOThsIa97pEDOxvGuRRgzG64bvtJ0938xuqzv18d3ZpQhstC"}, {"abcdefghijklmnopqrstuvwxyz", "$2a$8$aTsUwsyowQuzRrDqFflhgekJ8d9/7Z3GV3UcgvzQW3J5zMyrTvlz."}, }; } @Test(dataProvider = "hashes") public void testHash(final String password, final String expected) { final BCryptHashBean.BCryptParameters params = new BCryptHashBean.BCryptParameters(expected); final String hash = new BCryptHashBean(params.getCost()).hash(params.getSalt(), password); assertEquals(params.encode(hash), expected); } @Test(dataProvider = "hashes") public void testCompare(final String password, final String expected) { assertTrue(new BCryptHashBean(10).compare(expected, password)); } } cryptacular-1.2.5/src/test/java/org/cryptacular/bean/BufferedBlockCipherBeanTest.java000066400000000000000000000111341422604312300307020ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.bean; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.math.BigInteger; import java.security.KeyStore; import org.cryptacular.FailListener; import org.cryptacular.generator.Nonce; import org.cryptacular.generator.sp80038a.BigIntegerCounterNonce; import org.cryptacular.generator.sp80038a.LongCounterNonce; import org.cryptacular.generator.sp80038a.RBGNonce; import org.cryptacular.io.FileResource; import org.cryptacular.spec.BufferedBlockCipherSpec; import org.cryptacular.util.ByteUtil; import org.cryptacular.util.StreamUtil; import org.testng.annotations.DataProvider; import org.testng.annotations.Listeners; import org.testng.annotations.Test; import static org.testng.Assert.assertEquals; /** * Unit test for {@link BufferedBlockCipherBean}. * * @author Middleware Services */ @Listeners(FailListener.class) public class BufferedBlockCipherBeanTest { @DataProvider(name = "test-arrays") public Object[][] getTestArrays() { return new Object[][] { new Object[] { // Plaintext is NOT multiple of block size "Able was I ere I saw elba.", "AES/CBC/PKCS5", new RBGNonce(16), }, // Plaintext is multiple of block size new Object[] { "Four score and seven years ago, our forefathers ", "Blowfish/CBC/None", new RBGNonce(8), }, // OFB new Object[] { "Have you passed through this night?", "Blowfish/OFB/PKCS5Padding", new LongCounterNonce(), }, // CFB new Object[] { "I went to the woods because I wished to live deliberately, to front only the essential facts of life", "AES/CFB/PKCS5Padding", new RBGNonce(16), }, }; } @DataProvider(name = "test-streams") public Object[][] getTestStreams() { return new Object[][] { new Object[] { "src/test/resources/plaintexts/lorem-5000.txt", "AES/CBC/PKCS7", new RBGNonce(16), }, new Object[] { "src/test/resources/plaintexts/lorem-1200.txt", "Twofish/OFB/NULL", new BigIntegerCounterNonce(BigInteger.ONE, 16), }, new Object[] { "src/test/resources/plaintexts/lorem-1200.txt", "AES/CFB/PKCS5", new RBGNonce(16), }, new Object[] { "src/test/resources/plaintexts/lorem-1200.txt", "AES/ECB/PKCS5", new RBGNonce(16), }, }; } @Test(dataProvider = "test-arrays") public void testEncryptDecryptArray(final String input, final String cipherSpecString, final Nonce nonce) throws Exception { final BufferedBlockCipherBean cipherBean = new BufferedBlockCipherBean(); final BufferedBlockCipherSpec cipherSpec = BufferedBlockCipherSpec.parse(cipherSpecString); cipherBean.setNonce(nonce); cipherBean.setKeyAlias("vtcrypt"); cipherBean.setKeyPassword("vtcrypt"); cipherBean.setKeyStore(getTestKeyStore()); cipherBean.setBlockCipherSpec(cipherSpec); final byte[] ciphertext = cipherBean.encrypt(ByteUtil.toBytes(input)); assertEquals(ByteUtil.toString(cipherBean.decrypt(ciphertext)), input); } @Test(dataProvider = "test-streams") public void testEncryptDecryptStream(final String path, final String cipherSpecString, final Nonce nonce) throws Exception { final BufferedBlockCipherBean cipherBean = new BufferedBlockCipherBean(); final BufferedBlockCipherSpec cipherSpec = BufferedBlockCipherSpec.parse(cipherSpecString); cipherBean.setNonce(nonce); cipherBean.setKeyAlias("vtcrypt"); cipherBean.setKeyPassword("vtcrypt"); cipherBean.setKeyStore(getTestKeyStore()); cipherBean.setBlockCipherSpec(cipherSpec); final ByteArrayOutputStream tempOut = new ByteArrayOutputStream(8192); cipherBean.encrypt(StreamUtil.makeStream(new File(path)), tempOut); final ByteArrayInputStream tempIn = new ByteArrayInputStream(tempOut.toByteArray()); final ByteArrayOutputStream finalOut = new ByteArrayOutputStream(8192); cipherBean.decrypt(tempIn, finalOut); assertEquals(ByteUtil.toString(finalOut.toByteArray()), ByteUtil.toString(StreamUtil.readAll(path))); } private static KeyStore getTestKeyStore() { final KeyStoreFactoryBean bean = new KeyStoreFactoryBean(); bean.setPassword("vtcrypt"); bean.setResource(new FileResource(new File("src/test/resources/keystores/cipher-bean.jceks"))); bean.setType("JCEKS"); return bean.newInstance(); } } cryptacular-1.2.5/src/test/java/org/cryptacular/bean/EncodingHashBeanTest.java000066400000000000000000000060361422604312300274110ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.bean; import org.cryptacular.FailListener; import org.cryptacular.spec.CodecSpec; import org.cryptacular.spec.DigestSpec; import org.cryptacular.util.ByteUtil; import org.cryptacular.util.CodecUtil; import org.testng.annotations.DataProvider; import org.testng.annotations.Listeners; import org.testng.annotations.Test; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertTrue; /** * Unit test for {@link EncodingHashBean}. * * @author Middleware Services */ @Listeners(FailListener.class) public class EncodingHashBeanTest { @DataProvider(name = "hash-data") public Object[][] getHashData() { return new Object[][] { { new EncodingHashBean(CodecSpec.BASE64, new DigestSpec("SHA1"), 1, false), new Object[] { CodecUtil.b64("7FHsteHnm6XQsJT1TTKbxw=="), CodecUtil.b64("ehp6PCnojSegFpRvStqQ9A=="), }, "Oadnuuj7QsRPUuMBiu+dmlT6qzU=", }, { new EncodingHashBean(CodecSpec.BASE64, new DigestSpec("SHA1"), 1, true), new Object[] { CodecUtil.b64("7FHsteHnm6XQsJT1TTKbxw=="), CodecUtil.b64("ehp6PCnojSegFpRvStqQ9A=="), CodecUtil.b64("/siCJIPstwM="), }, "uRt+VlmPzfGOPjSGoZLTxpvd1dP+yIIkg+y3Aw==", }, { new EncodingHashBean(CodecSpec.HEX, new DigestSpec("SHA256"), 3, false), new Object[] { CodecUtil.b64("7FHsteHnm6XQsJT1TTKbxw=="), CodecUtil.b64("ehp6PCnojSegFpRvStqQ9A=="), }, "3a1edec6aef6d1736bec63130755690c07f04d7e7139d8fd685cc2d989961b79", }, { new EncodingHashBean(CodecSpec.HEX, new DigestSpec("SHA256"), 3, true), new Object[] { CodecUtil.b64("7FHsteHnm6XQsJT1TTKbxw=="), CodecUtil.b64("ehp6PCnojSegFpRvStqQ9A=="), CodecUtil.b64("DH9M1lDibNU="), }, "79f2868e7f72ed18cd67858e8ffe589c6090d696f7ff298e021faf5855fd41a10c7f4cd650e26cd5", }, }; } @DataProvider(name = "compare-data") public Object[][] getCompareData() { return new Object[][] { { new EncodingHashBean(CodecSpec.BASE64, new DigestSpec("SHA1"), 1, false), "7fyOZXGp+gKMziV/2Px7RIMkxyI2O1H8", new Object[] {ByteUtil.toBytes("password"), }, }, { new EncodingHashBean(CodecSpec.BASE64, new DigestSpec("SHA1"), 1, true), "lrb+YkKHqoGbFtxYd0B5567N6ZYwqwvWQwvoSg==", new Object[] {ByteUtil.toBytes("password"), }, }, }; } @Test(dataProvider = "hash-data") public void testHash(final EncodingHashBean bean, final Object[] input, final String expected) throws Exception { assertEquals(bean.hash(input), expected); } @Test(dataProvider = "compare-data") public void testCompare(final EncodingHashBean bean, final String hash, final Object[] input) throws Exception { assertTrue(bean.compare(hash, input)); } } cryptacular-1.2.5/src/test/java/org/cryptacular/bean/KeyStoreBasedKeyFactoryBeanTest.java000066400000000000000000000041341422604312300315610ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.bean; import java.io.File; import java.security.Key; import java.security.interfaces.RSAPrivateKey; import javax.crypto.SecretKey; import org.cryptacular.FailListener; import org.cryptacular.io.FileResource; import org.testng.annotations.DataProvider; import org.testng.annotations.Listeners; import org.testng.annotations.Test; import static org.testng.Assert.assertEquals; /** * Unit test for {@link KeyStoreBasedKeyFactoryBean}. * * @author Middleware Services */ @Listeners(FailListener.class) public class KeyStoreBasedKeyFactoryBeanTest { private static final String KS_PATH = "src/test/resources/keystores/"; @DataProvider(name = "keys") public Object[][] getKeys() { return new Object[][] { { KS_PATH + "factory-bean.jceks", "JCEKS", "aes256", "AES", 32, }, { KS_PATH + "factory-bean.jceks", "JCEKS", "rsa2048", "RSA", 2048, }, }; } @Test(dataProvider = "keys") public void testNewInstance( final String keyStorePath, final String keyStoreType, final String alias, final String expectedAlg, final int expectedSize) throws Exception { final KeyStoreFactoryBean keyStoreFactory = new KeyStoreFactoryBean(); keyStoreFactory.setResource(new FileResource(new File(keyStorePath))); keyStoreFactory.setPassword("vtcrypt"); keyStoreFactory.setType(keyStoreType); final KeyStoreBasedKeyFactoryBean secretKeyFactory = new KeyStoreBasedKeyFactoryBean(); secretKeyFactory.setKeyStore(keyStoreFactory.newInstance()); secretKeyFactory.setAlias(alias); secretKeyFactory.setPassword("vtcrypt"); final Key key = secretKeyFactory.newInstance(); assertEquals(key.getAlgorithm(), expectedAlg); if (key instanceof SecretKey) { assertEquals(key.getEncoded().length, expectedSize); } else if (key instanceof RSAPrivateKey) { assertEquals(((RSAPrivateKey) key).getModulus().bitLength(), expectedSize); } } } cryptacular-1.2.5/src/test/java/org/cryptacular/bean/KeyStoreFactoryBeanTest.java000066400000000000000000000030061422604312300301460ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.bean; import java.io.File; import org.cryptacular.FailListener; import org.cryptacular.io.FileResource; import org.cryptacular.io.Resource; import org.testng.annotations.DataProvider; import org.testng.annotations.Listeners; import org.testng.annotations.Test; import static org.testng.Assert.assertEquals; /** * Unit test for {@link KeyStoreFactoryBean}. * * @author Middleware Services */ @Listeners(FailListener.class) public class KeyStoreFactoryBeanTest { private static final String KS_PATH = "src/test/resources/keystores/"; @DataProvider(name = "keystore-data") public Object[][] getKeyStoreData() { return new Object[][] { new Object[] { "JCEKS", new FileResource(new File(KS_PATH + "keystore.jceks")), 1, }, new Object[] { "JKS", new FileResource(new File(KS_PATH + "keystore.jks")), 1, }, new Object[] { "PKCS12", new FileResource(new File(KS_PATH + "keystore.p12")), 1, }, }; } @Test(dataProvider = "keystore-data") public void testNewInstance(final String type, final Resource resource, final int expectedSize) throws Exception { final KeyStoreFactoryBean factory = new KeyStoreFactoryBean(); factory.setType(type); factory.setResource(resource); factory.setPassword("vtcrypt"); assertEquals(factory.newInstance().size(), expectedSize); } } cryptacular-1.2.5/src/test/java/org/cryptacular/bean/PemBasedPrivateKeyFactoryBeanTest.java000066400000000000000000000026401422604312300320700ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.bean; import java.io.File; import java.security.PrivateKey; import org.cryptacular.FailListener; import org.cryptacular.util.ByteUtil; import org.cryptacular.util.StreamUtil; import org.testng.annotations.DataProvider; import org.testng.annotations.Listeners; import org.testng.annotations.Test; import static org.testng.Assert.assertTrue; /** * Unit test for {@link PemBasedPrivateKeyFactoryBean}. * * @author Middleware Services */ @Listeners(FailListener.class) public class PemBasedPrivateKeyFactoryBeanTest { private static final String KEY_PATH = "src/test/resources/keys/"; @DataProvider(name = "keys") public Object[][] getKeys() { return new Object[][] { new Object[] {KEY_PATH + "dsa-pkcs8-nopass.pem"}, new Object[] {KEY_PATH + "dsa-openssl-nopass.pem"}, new Object[] {KEY_PATH + "rsa-pkcs8-nopass.pem"}, new Object[] {KEY_PATH + "rsa-openssl-nopass.pem"}, new Object[] {KEY_PATH + "ec-openssl-sect571r1-explicit-nopass.pem"}, }; } @Test(dataProvider = "keys") public void testNewInstance(final String path) throws Exception { final String pem = ByteUtil.toString(StreamUtil.readAll(new File(path))); final PemBasedPrivateKeyFactoryBean factory = new PemBasedPrivateKeyFactoryBean(pem); assertTrue(factory.newInstance() instanceof PrivateKey); } } cryptacular-1.2.5/src/test/java/org/cryptacular/bean/PemBasedPublicKeyFactoryBeanTest.java000066400000000000000000000024051422604312300316730ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.bean; import java.io.File; import java.security.PublicKey; import org.cryptacular.FailListener; import org.cryptacular.util.ByteUtil; import org.cryptacular.util.StreamUtil; import org.testng.annotations.DataProvider; import org.testng.annotations.Listeners; import org.testng.annotations.Test; import static org.testng.Assert.assertTrue; /** * Unit test for {@link PemBasedPublicKeyFactoryBean}. * * @author Middleware Services */ @Listeners(FailListener.class) public class PemBasedPublicKeyFactoryBeanTest { private static final String KEY_PATH = "src/test/resources/keys/"; @DataProvider(name = "keys") public Object[][] getKeys() { return new Object[][] { new Object[] {KEY_PATH + "dsa-pub.pem"}, new Object[] {KEY_PATH + "rsa-pub.pem"}, new Object[] {KEY_PATH + "ec-secp224k1-explicit-pub.pem"}, }; } @Test(dataProvider = "keys") public void testNewInstance(final String path) throws Exception { final String pem = ByteUtil.toString(StreamUtil.readAll(new File(path))); final PemBasedPublicKeyFactoryBean factory = new PemBasedPublicKeyFactoryBean(pem); assertTrue(factory.newInstance() instanceof PublicKey); } } cryptacular-1.2.5/src/test/java/org/cryptacular/bean/ResourceBasedPrivateKeyFactoryBeanTest.java000066400000000000000000000040221422604312300331320ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.bean; import java.io.File; import java.security.PrivateKey; import org.cryptacular.FailListener; import org.cryptacular.io.FileResource; import org.cryptacular.io.Resource; import org.testng.annotations.DataProvider; import org.testng.annotations.Listeners; import org.testng.annotations.Test; import static org.testng.Assert.assertTrue; /** * Unit test for {@link ResourceBasedPrivateKeyFactoryBean}. * * @author Middleware Services */ @Listeners(FailListener.class) public class ResourceBasedPrivateKeyFactoryBeanTest { private static final String KEY_PATH = "src/test/resources/keys/"; @DataProvider(name = "keys") public Object[][] getKeys() { return new Object[][] { new Object[] {KEY_PATH + "dsa-pkcs8-nopass.pem", null}, new Object[] {KEY_PATH + "dsa-openssl-nopass.pem", null}, new Object[] {KEY_PATH + "rsa-pkcs8-nopass.pem", null}, new Object[] {KEY_PATH + "rsa-openssl-nopass.pem", null}, new Object[] { KEY_PATH + "ec-openssl-sect571r1-explicit-nopass.pem", null, }, new Object[] {KEY_PATH + "dsa-openssl-des3.pem", "vtcrypt"}, new Object[] {KEY_PATH + "dsa-pkcs8-v2-des3.der", "vtcrypt"}, new Object[] { KEY_PATH + "ec-pkcs8-sect571r1-explicit-v2-aes128.pem", "vtcrypt", }, new Object[] { KEY_PATH + "ec-pkcs8-sect571r1-named-v1-sha1-rc2-64.der", "vtcrypt", }, new Object[] {KEY_PATH + "rsa-openssl-des.pem", "vtcrypt"}, new Object[] {KEY_PATH + "rsa-pkcs8-v2-aes256.der", "vtcrypt"}, }; } @Test(dataProvider = "keys") public void testNewInstance(final String path, final String password) throws Exception { final Resource resource = new FileResource(new File(path)); final ResourceBasedPrivateKeyFactoryBean factory = new ResourceBasedPrivateKeyFactoryBean(resource, password); assertTrue(factory.newInstance() instanceof PrivateKey); } } cryptacular-1.2.5/src/test/java/org/cryptacular/bean/ResourceBasedPublicKeyFactoryBeanTest.java000066400000000000000000000023471422604312300327460ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.bean; import java.security.PublicKey; import org.cryptacular.FailListener; import org.cryptacular.io.ClassPathResource; import org.cryptacular.io.Resource; import org.testng.annotations.DataProvider; import org.testng.annotations.Listeners; import org.testng.annotations.Test; import static org.testng.Assert.assertTrue; /** * Unit test for {@link ResourceBasedPublicKeyFactoryBean}. * * @author Middleware Services */ @Listeners(FailListener.class) public class ResourceBasedPublicKeyFactoryBeanTest { private static final String KEY_PATH = "/keys/"; @DataProvider(name = "keys") public Object[][] getKeys() { return new Object[][] { new Object[] {KEY_PATH + "dsa-pub.pem"}, new Object[] {KEY_PATH + "rsa-pub.pem"}, new Object[] {KEY_PATH + "ec-secp224k1-explicit-pub.pem"}, }; } @Test(dataProvider = "keys") public void testNewInstance(final String path) throws Exception { final Resource resource = new ClassPathResource(path); final ResourceBasedPublicKeyFactoryBean factory = new ResourceBasedPublicKeyFactoryBean(resource); assertTrue(factory.newInstance() instanceof PublicKey); } } cryptacular-1.2.5/src/test/java/org/cryptacular/bean/ResourceBasedSecretKeyFactoryBeanTest.java000066400000000000000000000024001422604312300327430ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.bean; import java.io.File; import org.cryptacular.FailListener; import org.cryptacular.io.FileResource; import org.cryptacular.io.Resource; import org.testng.annotations.DataProvider; import org.testng.annotations.Listeners; import org.testng.annotations.Test; import static org.testng.Assert.assertEquals; /** * Unit test for {@link ResourceBasedSecretKeyFactoryBean}. * * @author Middleware Services */ @Listeners(FailListener.class) public class ResourceBasedSecretKeyFactoryBeanTest { private static final String KEY_PATH = "src/test/resources/keys/"; @DataProvider(name = "keys") public Object[][] getKeys() { return new Object[][] { new Object[] { "AES", new FileResource(new File(KEY_PATH + "aes-128.key")), 16, }, }; } @Test(dataProvider = "keys") public void testNewInstance(final String algorithm, final Resource resource, final int expectedSize) throws Exception { final ResourceBasedSecretKeyFactoryBean factory = new ResourceBasedSecretKeyFactoryBean(); factory.setAlgorithm(algorithm); factory.setResource(resource); assertEquals(factory.newInstance().getEncoded().length, expectedSize); } } cryptacular-1.2.5/src/test/java/org/cryptacular/bean/SimpleHashBeanTest.java000066400000000000000000000030231422604312300271050ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.bean; import org.cryptacular.FailListener; import org.cryptacular.spec.DigestSpec; import org.cryptacular.util.CodecUtil; import org.testng.annotations.DataProvider; import org.testng.annotations.Listeners; import org.testng.annotations.Test; import static org.testng.Assert.assertEquals; /** * Unit test for {@link SimpleHashBean}. * * @author Middleware Services */ @Listeners(FailListener.class) public class SimpleHashBeanTest { @DataProvider(name = "test-data") public Object[][] getTestData() { return new Object[][] { { new DigestSpec("SHA1"), new Object[] { CodecUtil.b64("7FHsteHnm6XQsJT1TTKbxw=="), CodecUtil.b64("ehp6PCnojSegFpRvStqQ9A=="), }, 1, "Oadnuuj7QsRPUuMBiu+dmlT6qzU=", }, { new DigestSpec("SHA256"), new Object[] { CodecUtil.b64("7FHsteHnm6XQsJT1TTKbxw=="), CodecUtil.b64("ehp6PCnojSegFpRvStqQ9A=="), }, 3, "Oh7exq720XNr7GMTB1VpDAfwTX5xOdj9aFzC2YmWG3k=", }, }; } @Test(dataProvider = "test-data") public void testHash(final DigestSpec digest, final Object[] input, final int iterations, final String expectedBase64) throws Exception { final SimpleHashBean bean = new SimpleHashBean(); bean.setDigestSpec(digest); bean.setIterations(iterations); assertEquals(CodecUtil.b64(bean.hash(input)), expectedBase64); } } cryptacular-1.2.5/src/test/java/org/cryptacular/codec/000077500000000000000000000000001422604312300227315ustar00rootroot00000000000000cryptacular-1.2.5/src/test/java/org/cryptacular/codec/Base32DecoderTest.java000066400000000000000000000042061422604312300267430ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.codec; import java.nio.ByteBuffer; import java.nio.CharBuffer; import org.cryptacular.FailListener; import org.cryptacular.util.ByteUtil; import org.cryptacular.util.CodecUtil; import org.testng.annotations.DataProvider; import org.testng.annotations.Listeners; import org.testng.annotations.Test; import static org.testng.Assert.assertEquals; /** * Unit test for {@link Base64Decoder}. * * @author Middleware Services */ @Listeners(FailListener.class) public class Base32DecoderTest { @DataProvider(name = "encoded-data") public Object[][] getEncodedData() { final Base32Decoder unpadded = new Base32Decoder(); unpadded.setPaddedInput(false); return new Object[][] { // Multiple of 40 bits new Object[] { new Base32Decoder(), "TQSN7XJ4", CodecUtil.hex("9c24dfdd3c"), }, // Final quantum of encoding input is exactly 8 bits new Object[] { unpadded, "43H7CNN2EI", CodecUtil.hex("e6cff135ba22"), }, // Final quantum of encoding input is exactly 16 bits new Object[] { new Base32Decoder(), "2NEK2FDJHXDQ====", CodecUtil.hex("d348ad14693dc7"), }, // Final quantum of encoding input is exactly 24 bits new Object[] { new Base32Decoder(), "LVVECZIT6F3MU===", CodecUtil.hex("5d6a416513f176ca"), }, // Final quantum of encoding input is exactly 32 bits new Object[] { new Base32Decoder(), "QN5Z7HN4PBY4G5Q=", CodecUtil.hex("837b9f9dbc7871c376"), }, }; } @Test(dataProvider = "encoded-data") public void testDecode(final Base32Decoder decoder, final String data, final byte[] expected) throws Exception { final CharBuffer input = CharBuffer.wrap(data); final ByteBuffer output = ByteBuffer.allocate(decoder.outputSize(input.length())); decoder.decode(input, output); decoder.finalize(output); output.flip(); assertEquals(ByteUtil.toArray(output), expected); } } cryptacular-1.2.5/src/test/java/org/cryptacular/codec/Base32EncoderTest.java000066400000000000000000000041151422604312300267540ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.codec; import java.nio.ByteBuffer; import java.nio.CharBuffer; import org.cryptacular.FailListener; import org.cryptacular.util.CodecUtil; import org.testng.annotations.DataProvider; import org.testng.annotations.Listeners; import org.testng.annotations.Test; import static org.testng.Assert.assertEquals; /** * Unit test for {@link Base64Encoder}. * * @author Middleware Services */ @Listeners(FailListener.class) public class Base32EncoderTest { @DataProvider(name = "byte-data") public Object[][] getByteData() { final Base32Encoder unpadded = new Base32Encoder(); unpadded.setPaddedOutput(false); return new Object[][] { // Multiple of 40 bits new Object[] { new Base32Encoder(), CodecUtil.hex("9c24dfdd3c"), "TQSN7XJ4", }, // Final quantum of encoding input is exactly 8 bits new Object[] { new Base32Encoder(), CodecUtil.hex("e6cff135ba22"), "43H7CNN2EI======", }, // Final quantum of encoding input is exactly 16 bits new Object[] { new Base32Encoder(), CodecUtil.hex("d348ad14693dc7"), "2NEK2FDJHXDQ====", }, // Final quantum of encoding input is exactly 24 bits new Object[] { unpadded, CodecUtil.hex("5d6a416513f176ca"), "LVVECZIT6F3MU", }, // Final quantum of encoding input is exactly 32 bits new Object[] { new Base32Encoder(), CodecUtil.hex("837b9f9dbc7871c376"), "QN5Z7HN4PBY4G5Q=", }, }; } @Test(dataProvider = "byte-data") public void testEncode(final Base32Encoder encoder, final byte[] inBytes, final String expected) throws Exception { final ByteBuffer input = ByteBuffer.wrap(inBytes); final CharBuffer output = CharBuffer.allocate(encoder.outputSize(input.limit())); encoder.encode(input, output); encoder.finalize(output); assertEquals(output.flip().toString(), expected); } } cryptacular-1.2.5/src/test/java/org/cryptacular/codec/Base64DecoderTest.java000066400000000000000000000072141422604312300267520ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.codec; import java.io.File; import java.io.Reader; import java.nio.ByteBuffer; import java.nio.CharBuffer; import org.cryptacular.FailListener; import org.cryptacular.util.ByteUtil; import org.cryptacular.util.CodecUtil; import org.cryptacular.util.HashUtil; import org.cryptacular.util.StreamUtil; import org.testng.annotations.DataProvider; import org.testng.annotations.Listeners; import org.testng.annotations.Test; import static org.testng.Assert.assertEquals; /** * Unit test for {@link Base64Decoder} class. * * @author Middleware Services */ @Listeners(FailListener.class) public class Base64DecoderTest { @DataProvider(name = "encoded-data") public Object[][] getEncodedData() { return new Object[][] { new Object[] { new Base64Decoder(), "QWJsZSB3YXMgSSBlcmUgSSBzYXcgZWxiYQ==", ByteUtil.toBytes("Able was I ere I saw elba"), }, new Object[] { new Base64Decoder(), "QWJsZSB3YXMgSSBlcmUgSSBzYXcgZWxiYS4=", ByteUtil.toBytes("Able was I ere I saw elba."), }, new Object[] { new Base64Decoder(), "safx/LW8+SsSy/o3PmCNy4VEm5s=", HashUtil.sha1(ByteUtil.toBytes("t3stUs3r01")), }, new Object[] { new Base64Decoder.Builder().setUrlSafe(true).build(), "safx_LW8-SsSy_o3PmCNy4VEm5s=", HashUtil.sha1(ByteUtil.toBytes("t3stUs3r01")), }, new Object[] { new Base64Decoder.Builder().setUrlSafe(true).setPadding(false).build(), "FPu_A9l-", CodecUtil.hex("14FBBF03D97E"), }, new Object[] { new Base64Decoder.Builder().setUrlSafe(true).setPadding(false).build(), "FPu_A9k", CodecUtil.hex("14FBBF03D9"), }, }; } @DataProvider(name = "plaintext-files") public Object[][] getPlaintextFiles() { return new Object[][] { new Object[] {"src/test/resources/plaintexts/lorem-1190.txt"}, new Object[] {"src/test/resources/plaintexts/lorem-1200.txt"}, new Object[] {"src/test/resources/plaintexts/lorem-5000.txt"}, }; } @Test(dataProvider = "encoded-data") public void testDecode(final Base64Decoder decoder, final String data, final byte[] expected) throws Exception { final CharBuffer input = CharBuffer.wrap(data); final ByteBuffer output = ByteBuffer.allocate(decoder.outputSize(input.length())); decoder.decode(input, output); decoder.finalize(output); output.flip(); assertEquals(ByteUtil.toArray(output), expected); } @Test(dataProvider = "plaintext-files") public void testDecodeFile(final String path) throws Exception { final String expected = StreamUtil.readAll(StreamUtil.makeReader(new File(path))); final File file = new File(path + ".b64"); final StringBuilder actual = new StringBuilder(expected.length()); final Reader reader = StreamUtil.makeReader(file); final Base64Decoder decoder = new Base64Decoder(); try { final CharBuffer bufIn = CharBuffer.allocate(1024); final ByteBuffer bufOut = ByteBuffer.allocate(decoder.outputSize(bufIn.capacity())); while (reader.read(bufIn) > 0) { bufIn.flip(); decoder.decode(bufIn, bufOut); bufOut.flip(); actual.append(ByteUtil.toCharBuffer(bufOut)); bufOut.clear(); bufIn.clear(); } decoder.finalize(bufOut); bufOut.flip(); actual.append(ByteUtil.toCharBuffer(bufOut)); } finally { StreamUtil.closeReader(reader); } assertEquals(actual.toString(), expected); } } cryptacular-1.2.5/src/test/java/org/cryptacular/codec/Base64EncoderTest.java000066400000000000000000000102211422604312300267540ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.codec; import java.io.File; import java.io.FileInputStream; import java.nio.ByteBuffer; import java.nio.CharBuffer; import java.nio.channels.FileChannel; import org.cryptacular.FailListener; import org.cryptacular.util.ByteUtil; import org.cryptacular.util.CodecUtil; import org.cryptacular.util.HashUtil; import org.cryptacular.util.StreamUtil; import org.testng.annotations.DataProvider; import org.testng.annotations.Listeners; import org.testng.annotations.Test; import static org.testng.Assert.assertEquals; /** * Unit test for {@link Base64Encoder} class. * * @author Middleware Services */ @Listeners(FailListener.class) public class Base64EncoderTest { @DataProvider(name = "byte-data") public Object[][] getByteData() { final Base64Encoder unpadded = new Base64Encoder(); unpadded.setPaddedOutput(false); return new Object[][] { new Object[] { new Base64Encoder(), ByteUtil.toBytes("Able was I ere I saw elba"), "QWJsZSB3YXMgSSBlcmUgSSBzYXcgZWxiYQ==", }, new Object[] { new Base64Encoder.Builder().setPadding(false).build(), ByteUtil.toBytes("Able was I ere I saw elba"), "QWJsZSB3YXMgSSBlcmUgSSBzYXcgZWxiYQ", }, new Object[] { new Base64Encoder(), ByteUtil.toBytes("Able was I ere I saw elba."), "QWJsZSB3YXMgSSBlcmUgSSBzYXcgZWxiYS4=", }, new Object[] { new Base64Encoder(), HashUtil.sha1(ByteUtil.toBytes("t3stUs3r01")), "safx/LW8+SsSy/o3PmCNy4VEm5s=", }, new Object[] { new Base64Encoder(true), HashUtil.sha1(ByteUtil.toBytes("t3stUs3r01")), "safx_LW8-SsSy_o3PmCNy4VEm5s=", }, new Object[] { new Base64Encoder(), CodecUtil.hex("3f1c435a244f7a8be1572a1bf2a196f4958cc00c17b96e"), "PxxDWiRPeovhVyob8qGW9JWMwAwXuW4=", }, new Object[] { new Base64Encoder.Builder().setUrlSafe(true).setPadding(false).build(), CodecUtil.hex("14FBBF03D97E"), "FPu_A9l-", }, new Object[] { new Base64Encoder.Builder().setUrlSafe(true).setPadding(false).build(), CodecUtil.hex("14FBBF03D9"), "FPu_A9k", }, }; } @DataProvider(name = "plaintext-files") public Object[][] getPlaintextFiles() { return new Object[][] { new Object[] {"src/test/resources/plaintexts/lorem-1190.txt"}, new Object[] {"src/test/resources/plaintexts/lorem-1200.txt"}, new Object[] {"src/test/resources/plaintexts/lorem-5000.txt"}, }; } @Test(dataProvider = "byte-data") public void testEncode(final Base64Encoder encoder, final byte[] inBytes, final String expected) throws Exception { final ByteBuffer input = ByteBuffer.wrap(inBytes); final CharBuffer output = CharBuffer.allocate(encoder.outputSize(input.limit())); encoder.encode(input, output); encoder.finalize(output); assertEquals(output.flip().toString(), expected); } @Test(dataProvider = "plaintext-files") public void testEncodeFile(final String path) throws Exception { final File file = new File(path); String expectedPath = path + ".b64"; if ("\r\n".equals(System.lineSeparator())) { expectedPath += ".crlf"; } final String expected = new String(StreamUtil.readAll(expectedPath)); final StringBuilder actual = new StringBuilder(expected.length()); final Base64Encoder encoder = new Base64Encoder(64); try (FileInputStream input = new FileInputStream(file)) { final ByteBuffer bufIn = ByteBuffer.allocate(512); final CharBuffer bufOut = CharBuffer.allocate(encoder.outputSize(512)); final FileChannel chIn = input.getChannel(); while (chIn.read(bufIn) > 0) { bufIn.flip(); encoder.encode(bufIn, bufOut); bufOut.flip(); actual.append(bufOut); bufOut.clear(); bufIn.clear(); } encoder.finalize(bufOut); bufOut.flip(); actual.append(bufOut); } assertEquals(actual.toString(), expected); } } cryptacular-1.2.5/src/test/java/org/cryptacular/codec/HexDecoderTest.java000066400000000000000000000040121422604312300264430ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.codec; import java.nio.ByteBuffer; import java.nio.CharBuffer; import org.cryptacular.FailListener; import org.cryptacular.util.ByteUtil; import org.testng.annotations.DataProvider; import org.testng.annotations.Listeners; import org.testng.annotations.Test; import static org.testng.Assert.assertEquals; /** * Unit test for {@link HexDecoder} class. * * @author Middleware Services */ @Listeners(FailListener.class) public class HexDecoderTest { @DataProvider(name = "hex-data") public Object[][] getHexData() { return new Object[][] { new Object[] { "41626C652077617320492065726520492073617720656C6261", "Able was I ere I saw elba", }, new Object[] { "41626c652 077617320492065726520492073617720656c626\n1", "Able was I ere I saw elba", }, new Object[] { "41626c652 077617320492065726520492073617720656c626\n", "Able was I ere I saw elb", }, new Object[] { "41:62:6c:65:20:77:61:73:20:49:20:65:72:65:20:49:20:73:61:77:20:65:6c:62:61", "Able was I ere I saw elba", }, new Object[] { "9c63b0547798b60d5e04", ByteUtil.toString( new byte[] { (byte) -100, (byte) 99, (byte) -80, (byte) 84, (byte) 119, (byte) -104, (byte) -74, (byte) 13, (byte) 94, (byte) 4, }), }, }; } @Test(dataProvider = "hex-data") public void testDecode(final String encoded, final String expected) throws Exception { final HexDecoder decoder = new HexDecoder(); final ByteBuffer output = ByteBuffer.allocate(decoder.outputSize(encoded.length())); decoder.decode(CharBuffer.wrap(encoded), output); decoder.finalize(output); output.flip(); assertEquals(ByteUtil.toString(output), expected); } } cryptacular-1.2.5/src/test/java/org/cryptacular/codec/HexEncoderTest.java000066400000000000000000000042531422604312300264640ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.codec; import java.nio.ByteBuffer; import java.nio.CharBuffer; import org.cryptacular.FailListener; import org.cryptacular.util.ByteUtil; import org.testng.annotations.DataProvider; import org.testng.annotations.Listeners; import org.testng.annotations.Test; import static org.testng.Assert.assertEquals; /** * Unit test for {@link HexEncoder} class. * * @author Middleware Services */ @Listeners(FailListener.class) public class HexEncoderTest { @DataProvider(name = "text-data") public Object[][] getTextData() { return new Object[][] { new Object[] { new HexEncoder(false), ByteUtil.toBytes("Able was I ere I saw elba"), "41626c652077617320492065726520492073617720656c6261", }, new Object[] { new HexEncoder(false, true), ByteUtil.toBytes("Able was I ere I saw elba\n"), "41626C652077617320492065726520492073617720656C62610A", }, new Object[] { new HexEncoder(true), ByteUtil.toBytes("Able was I ere I saw elba"), "41:62:6c:65:20:77:61:73:20:49:20:65:72:65:20:49:20:73:61:77:20:65:6c:62:61", }, new Object[] { new HexEncoder(true, true), ByteUtil.toBytes("Able was I ere I saw elba"), "41:62:6C:65:20:77:61:73:20:49:20:65:72:65:20:49:20:73:61:77:20:65:6C:62:61", }, new Object[] { new HexEncoder(), new byte[] { (byte) -100, (byte) 99, (byte) -80, (byte) 84, (byte) 119, (byte) -104, (byte) -74, (byte) 13, (byte) 94, (byte) 4, }, "9c63b0547798b60d5e04", }, }; } @Test(dataProvider = "text-data") public void testEncode(final HexEncoder encoder, final byte[] data, final String expected) throws Exception { final CharBuffer output = CharBuffer.allocate(encoder.outputSize(data.length)); encoder.encode(ByteBuffer.wrap(data), output); encoder.finalize(output); assertEquals(output.flip().toString(), expected); } } cryptacular-1.2.5/src/test/java/org/cryptacular/generator/000077500000000000000000000000001422604312300236425ustar00rootroot00000000000000cryptacular-1.2.5/src/test/java/org/cryptacular/generator/HOTPGeneratorTest.java000066400000000000000000000030351422604312300277670ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.generator; import org.cryptacular.FailListener; import org.cryptacular.util.CodecUtil; import org.testng.annotations.DataProvider; import org.testng.annotations.Listeners; import org.testng.annotations.Test; import static org.testng.Assert.assertEquals; /** * Unit test for {@link HOTPGenerator}. * * @author Middleware Services */ @Listeners(FailListener.class) public class HOTPGeneratorTest { @DataProvider(name = "test-data") public Object[][] getTestData() { return new Object[][] { {"0x3132333435363738393031323334353637383930", 0, 755224}, {"0x3132333435363738393031323334353637383930", 1, 287082}, {"0x3132333435363738393031323334353637383930", 2, 359152}, {"0x3132333435363738393031323334353637383930", 3, 969429}, {"0x3132333435363738393031323334353637383930", 4, 338314}, {"0x3132333435363738393031323334353637383930", 5, 254676}, {"0x3132333435363738393031323334353637383930", 6, 287922}, {"0x3132333435363738393031323334353637383930", 7, 162583}, {"0x3132333435363738393031323334353637383930", 8, 399871}, {"0x3132333435363738393031323334353637383930", 9, 520489}, }; } @Test(dataProvider = "test-data") public void testGenerate(final String hexKey, final int count, final int expected) throws Exception { final HOTPGenerator generator = new HOTPGenerator(); assertEquals(generator.generate(CodecUtil.hex(hexKey), count), expected); } } cryptacular-1.2.5/src/test/java/org/cryptacular/generator/RandomIdGeneratorTest.java000066400000000000000000000065221422604312300307160ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.generator; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.cryptacular.FailListener; import org.testng.annotations.DataProvider; import org.testng.annotations.Listeners; import org.testng.annotations.Test; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertNotNull; import static org.testng.Assert.assertTrue; /** * Unit test for {@link RandomIdGenerator}. * * @author Middleware Services */ @Listeners(FailListener.class) public class RandomIdGeneratorTest { @DataProvider(name = "generators") public Object[][] getGenerators() { return new Object[][] { { new RandomIdGenerator(10), Pattern.compile("\\w{10}"), }, { new RandomIdGenerator(128), Pattern.compile("\\w{128}"), }, { new RandomIdGenerator(20, "abcdefg"), Pattern.compile("[abcdefg]{20}"), }, }; } @Test(dataProvider = "generators") public void testGenerate(final RandomIdGenerator generator, final Pattern expected) { for (int i = 0; i < 100; i++) { final Matcher m = expected.matcher(generator.generate()); assertTrue(m.matches()); } } /** * Test concurrent random ID generation on a shared instance. * * @throws Exception on test errors */ @Test public void testConcurrentGeneration() throws Exception { final int poolSize = 100; final ExecutorService executor = Executors.newFixedThreadPool(poolSize); final RandomIdGenerator generator = new RandomIdGenerator(50); final Collection> tasks = new ArrayList<>(); for (int i = 0; i < poolSize; i++) { tasks.add(generator::generate); } // Ensure all generated IDs are unique final Set identifiers = new HashSet<>(poolSize); final List> results = executor.invokeAll(tasks); for (Future result : results) { final String id = result.get(1, TimeUnit.SECONDS); assertNotNull(id); identifiers.add(id); } assertEquals(poolSize, identifiers.size()); } /** * Test creating new instances and calling generate on them concurrently. * * @throws Exception on test errors */ @Test public void testConcurrentGeneration2() throws Exception { final int poolSize = 100; final ExecutorService executor = Executors.newFixedThreadPool(poolSize); final Collection> tasks = new ArrayList<>(); for (int i = 0; i < poolSize; i++) { tasks.add(() -> new RandomIdGenerator(50).generate()); } // Ensure all generated IDs are unique final Set identifiers = new HashSet<>(poolSize); final List> results = executor.invokeAll(tasks); for (Future result : results) { final String id = result.get(1, TimeUnit.SECONDS); assertNotNull(id); identifiers.add(id); } assertEquals(poolSize, identifiers.size()); } } cryptacular-1.2.5/src/test/java/org/cryptacular/generator/TOTPGeneratorTest.java000066400000000000000000000062701422604312300300070ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.generator; import java.nio.charset.StandardCharsets; import org.cryptacular.FailListener; import org.cryptacular.spec.DigestSpec; import org.testng.annotations.DataProvider; import org.testng.annotations.Listeners; import org.testng.annotations.Test; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertTrue; /** * Unit test for {@link HOTPGenerator}. * * @author Middleware Services */ @Listeners(FailListener.class) public class TOTPGeneratorTest { /** Test vectors from RFC 6238, appendix B. */ @DataProvider(name = "test-data-rfc6238") public Object[][] getTestDataRfc6238() { // Key size is equal to hash length for test vectors in RFC-6238 // (via careful review of the main method in the reference implementation under Appendix A) final String sha1Key = "12345678901234567890"; final String sha256Key = "12345678901234567890123456789012"; final String sha512Key = "1234567890123456789012345678901234567890123456789012345678901234"; return new Object[][] { {new DigestSpec("SHA1"), sha1Key, 59, 8, 94287082}, {new DigestSpec("SHA256"), sha256Key, 59, 8, 46119246}, {new DigestSpec("SHA512"), sha512Key, 59, 8, 90693936}, {new DigestSpec("SHA1"), sha1Key, 1111111109, 8, 7081804}, {new DigestSpec("SHA256"), sha256Key, 1111111109, 8, 68084774}, {new DigestSpec("SHA512"), sha512Key, 1111111109, 8, 25091201}, {new DigestSpec("SHA1"), sha1Key, 1111111111, 8, 14050471}, {new DigestSpec("SHA256"), sha256Key, 1111111111, 8, 67062674}, {new DigestSpec("SHA512"), sha512Key, 1111111111, 8, 99943326}, {new DigestSpec("SHA1"), sha1Key, 1234567890, 8, 89005924}, {new DigestSpec("SHA256"), sha256Key, 1234567890, 8, 91819424}, {new DigestSpec("SHA512"), sha512Key, 1234567890, 8, 93441116}, {new DigestSpec("SHA1"), sha1Key, 2000000000, 8, 69279037}, {new DigestSpec("SHA256"), sha256Key, 2000000000, 8, 90698825}, {new DigestSpec("SHA512"), sha512Key, 2000000000, 8, 38618901}, {new DigestSpec("SHA1"), sha1Key, 20000000000L, 8, 65353130}, {new DigestSpec("SHA256"), sha256Key, 20000000000L, 8, 77737706}, {new DigestSpec("SHA512"), sha512Key, 20000000000L, 8, 47863826}, }; } @Test(dataProvider = "test-data-rfc6238") public void testGenerate( final DigestSpec digestSpec, final String asciiKey, final long currentTime, final int otpSize, final int expected) { final TOTPGenerator generator = new TOTPGenerator(); generator.setDigestSpecification(digestSpec); generator.setStartTime(0); generator.setTimeStep(30); generator.setCurrentTime(currentTime); generator.setNumberOfDigits(otpSize); assertEquals(generator.generate(asciiKey.getBytes(StandardCharsets.US_ASCII)), expected); } /** Ensure the system time is used by default. */ @Test public void testTimeBehavior() throws Exception { final TOTPGenerator generator = new TOTPGenerator(); final long t1 = generator.currentTime(); Thread.sleep(1001); final long t2 = generator.currentTime(); assertTrue(t2 > t1); } } cryptacular-1.2.5/src/test/java/org/cryptacular/generator/sp80038a/000077500000000000000000000000001422604312300250305ustar00rootroot00000000000000cryptacular-1.2.5/src/test/java/org/cryptacular/generator/sp80038a/BigIntegerCounterNonceTest.java000066400000000000000000000022301422604312300330720ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.generator.sp80038a; import java.math.BigInteger; import org.cryptacular.FailListener; import org.cryptacular.util.ByteUtil; import org.testng.annotations.DataProvider; import org.testng.annotations.Listeners; import org.testng.annotations.Test; import static org.testng.Assert.assertEquals; /** * Unit test for {@link BigIntegerCounterNonce}. * * @author Middleware Services */ @Listeners(FailListener.class) public class BigIntegerCounterNonceTest { @DataProvider(name = "test-data") public Object[][] getTestData() { return new Object[][] { new Object[] {1, 8}, new Object[] {2199023255552L, 16}, }; } @Test(dataProvider = "test-data") public void testGenerate(final long start, final int expectedLength) throws Exception { final BigIntegerCounterNonce nonce = new BigIntegerCounterNonce( new BigInteger(ByteUtil.toBytes(start)), expectedLength); final byte[] value = nonce.generate(); assertEquals(value.length, expectedLength); assertEquals(new BigInteger(value), new BigInteger(ByteUtil.toBytes(start + 1))); } } cryptacular-1.2.5/src/test/java/org/cryptacular/io/000077500000000000000000000000001422604312300222635ustar00rootroot00000000000000cryptacular-1.2.5/src/test/java/org/cryptacular/io/DecodingInputStreamTest.java000066400000000000000000000030261422604312300276770ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.io; import java.io.ByteArrayOutputStream; import java.io.File; import org.bouncycastle.util.io.Streams; import org.cryptacular.FailListener; import org.cryptacular.util.ByteUtil; import org.cryptacular.util.StreamUtil; import org.testng.annotations.DataProvider; import org.testng.annotations.Listeners; import org.testng.annotations.Test; import static org.testng.Assert.assertEquals; /** * Unit test for {@link DecodingInputStream} class. * * @author Middleware Services */ @Listeners(FailListener.class) public class DecodingInputStreamTest { @DataProvider(name = "plaintext-files") public Object[][] getPlaintextFiles() { return new Object[][] { new Object[] {"src/test/resources/plaintexts/lorem-1200.txt"}, new Object[] {"src/test/resources/plaintexts/lorem-5000.txt"}, }; } @Test(dataProvider = "plaintext-files") public void testDecode(final String path) throws Exception { final String expected = StreamUtil.readAll(StreamUtil.makeReader(new File(path))); final File file = new File(path + ".b64"); final DecodingInputStream input = DecodingInputStream.base64(StreamUtil.makeStream(file)); final ByteArrayOutputStream output = new ByteArrayOutputStream(expected.length()); try { Streams.pipeAll(input, output); } finally { StreamUtil.closeStream(input); StreamUtil.closeStream(output); } assertEquals(ByteUtil.toString(output.toByteArray()), expected); } } cryptacular-1.2.5/src/test/java/org/cryptacular/io/EncodingOutputStreamTest.java000066400000000000000000000031571422604312300301170ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.io; import java.io.ByteArrayOutputStream; import java.io.File; import org.bouncycastle.util.io.Streams; import org.cryptacular.FailListener; import org.cryptacular.util.ByteUtil; import org.cryptacular.util.StreamUtil; import org.testng.annotations.DataProvider; import org.testng.annotations.Listeners; import org.testng.annotations.Test; import static org.testng.Assert.assertEquals; /** * Unit test for {@link EncodingOutputStream} class. * * @author Middleware Services */ @Listeners(FailListener.class) public class EncodingOutputStreamTest { @DataProvider(name = "plaintext-files") public Object[][] getPlaintextFiles() { return new Object[][] { new Object[] {"src/test/resources/plaintexts/lorem-1200.txt"}, new Object[] {"src/test/resources/plaintexts/lorem-5000.txt"}, }; } @Test(dataProvider = "plaintext-files") public void testEncode(final String path) throws Exception { final File file = new File(path); String expectedPath = path + ".b64"; if ("\r\n".equals(System.lineSeparator())) { expectedPath += ".crlf"; } final String expected = new String(StreamUtil.readAll(expectedPath)); final ByteArrayOutputStream bufOut = new ByteArrayOutputStream((int) file.length() * 4 / 3); final EncodingOutputStream output = EncodingOutputStream.base64(bufOut, 64); try { Streams.pipeAll(StreamUtil.makeStream(file), output); } finally { StreamUtil.closeStream(output); } assertEquals(ByteUtil.toString(bufOut.toByteArray()), expected); } } cryptacular-1.2.5/src/test/java/org/cryptacular/util/000077500000000000000000000000001422604312300226315ustar00rootroot00000000000000cryptacular-1.2.5/src/test/java/org/cryptacular/util/ByteUtilTest.java000066400000000000000000000025501422604312300260770ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.util; import org.cryptacular.FailListener; import org.testng.annotations.DataProvider; import org.testng.annotations.Listeners; import org.testng.annotations.Test; import static org.testng.Assert.assertEquals; /** @author Middleware Services */ @Listeners(FailListener.class) public class ByteUtilTest { @DataProvider(name = "integers") public Object[][] getIntegers() { return new Object[][] { new Object[] {64}, new Object[] {-89}, new Object[] {255}, new Object[] {256}, new Object[] {210983498}, new Object[] {-417234198}, }; } @DataProvider(name = "longs") public Object[][] getLongs() { return new Object[][] { new Object[] {128}, new Object[] {110374187198L}, new Object[] {-8987189751341L}, }; } @Test(dataProvider = "integers") public void testIntToBytesAndBack(final int value) throws Exception { final byte[] bytes = new byte[4]; ByteUtil.toBytes(value, bytes, 0); assertEquals(ByteUtil.toInt(bytes), value); } @Test(dataProvider = "longs") public void testLongToBytesAndBack(final long value) throws Exception { final byte[] bytes = new byte[8]; ByteUtil.toBytes(value, bytes, 0); assertEquals(ByteUtil.toLong(bytes), value); } } cryptacular-1.2.5/src/test/java/org/cryptacular/util/CertUtilTest.java000066400000000000000000000243151422604312300260740ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.util; import java.security.PrivateKey; import java.security.cert.X509Certificate; import java.util.List; import org.bouncycastle.asn1.x509.GeneralNames; import org.bouncycastle.asn1.x509.KeyPurposeId; import org.cryptacular.FailListener; import org.cryptacular.x509.GeneralNameType; import org.cryptacular.x509.KeyUsageBits; import org.testng.annotations.DataProvider; import org.testng.annotations.Listeners; import org.testng.annotations.Test; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertNull; import static org.testng.Assert.assertTrue; /** * Unit test for {@link CertUtil} class. * * @author Middleware Services */ @Listeners(FailListener.class) public class CertUtilTest { private static final String CRT_PATH = "src/test/resources/certs/"; @DataProvider(name = "subject-cn") public Object[][] getSubjectCommonNames() { return new Object[][] { new Object[] { CertUtil.readCertificate(CRT_PATH + "ed.middleware.vt.edu.crt"), "ed.middleware.vt.edu", }, }; } @DataProvider(name = "subject-alt-names") public Object[][] getSubjectAltNames() { return new Object[][] { new Object[] { CertUtil.readCertificate(CRT_PATH + "ed.middleware.vt.edu.crt"), new String[] { "ed.middleware.vt.edu", "directory.vt.edu", "id.directory.vt.edu", "authn.directory.vt.edu", "ldap.vt.edu", }, }, }; } @DataProvider(name = "subject-alt-names-by-type") public Object[][] getSubjectAltNamesByType() { return new Object[][] { new Object[] { CertUtil.readCertificate(CRT_PATH + "ed.middleware.vt.edu.crt"), new GeneralNameType[] {GeneralNameType.DNSName}, new String[] { "ed.middleware.vt.edu", "directory.vt.edu", "id.directory.vt.edu", "authn.directory.vt.edu", "ldap.vt.edu", }, }, new Object[] { CertUtil.readCertificate(CRT_PATH + "ed.middleware.vt.edu.crt"), new GeneralNameType[] {GeneralNameType.RFC822Name}, new String[0], }, }; } @DataProvider(name = "subject-names") public Object[][] getSubjectNames() { return new Object[][] { new Object[] { CertUtil.readCertificate(CRT_PATH + "serac-dev-test.crt"), new String[] {"Marvin S Addison", "eprov@vt.edu"}, }, }; } @DataProvider(name = "subject-names-by-type") public Object[][] getSubjectNamesByType() { return new Object[][] { new Object[] { CertUtil.readCertificate(CRT_PATH + "serac-dev-test.crt"), new GeneralNameType[] {GeneralNameType.RFC822Name}, new String[] {"Marvin S Addison", "eprov@vt.edu"}, }, new Object[] { CertUtil.readCertificate(CRT_PATH + "serac-dev-test.crt"), new GeneralNameType[] {GeneralNameType.OtherName}, new String[] {"Marvin S Addison"}, }, }; } @DataProvider(name = "entity-certificate") public Object[][] getEntityCertificates() throws Exception { return new Object[][] { new Object[] { KeyPairUtil.readPrivateKey(CRT_PATH + "entity.key"), new X509Certificate[] { CertUtil.readCertificate(CRT_PATH + "glider.cc.vt.edu.crt"), CertUtil.readCertificate(CRT_PATH + "login.live.com.crt"), CertUtil.readCertificate(CRT_PATH + "entity.crt"), }, CertUtil.readCertificate(CRT_PATH + "entity.crt"), }, }; } @DataProvider(name = "basic-usage") public Object[][] getBasicUsage() throws Exception { return new Object[][] { new Object[] { CertUtil.readCertificate(CRT_PATH + "serac-dev-test.crt"), new KeyUsageBits[] { KeyUsageBits.DigitalSignature, KeyUsageBits.NonRepudiation, }, }, new Object[] { CertUtil.readCertificate(CRT_PATH + "login.live.com.crt"), new KeyUsageBits[] { KeyUsageBits.DigitalSignature, KeyUsageBits.KeyEncipherment, }, }, }; } @DataProvider(name = "extended-usage") public Object[][] getExtendedUsage() throws Exception { return new Object[][] { new Object[] { CertUtil.readCertificate(CRT_PATH + "serac-dev-test.crt"), new KeyPurposeId[] { KeyPurposeId.id_kp_clientAuth, KeyPurposeId.id_kp_emailProtection, KeyPurposeId.id_kp_smartcardlogon, }, }, new Object[] { CertUtil.readCertificate(CRT_PATH + "login.live.com.crt"), new KeyPurposeId[] { KeyPurposeId.id_kp_clientAuth, KeyPurposeId.id_kp_serverAuth, }, }, }; } @DataProvider(name = "has-policies") public Object[][] getHasPolicies() throws Exception { return new Object[][] { new Object[] { CertUtil.readCertificate(CRT_PATH + "serac-dev-test.crt"), new String[] { "1.3.6.1.4.1.6760.5.2.2.1.1", "1.3.6.1.4.1.6760.5.2.2.2.1", "1.3.6.1.4.1.6760.5.2.2.3.1", "1.3.6.1.4.1.6760.5.2.2.4.1", }, }, }; } @DataProvider(name = "subject-keyid") public Object[][] getSubjectKeyId() throws Exception { return new Object[][] { new Object[] { CertUtil.readCertificate(CRT_PATH + "serac-dev-test.crt"), "25:48:2F:28:EC:5D:19:BB:1D:25:AE:94:93:B1:7B:B5:35:96:24:66", }, new Object[] { CertUtil.readCertificate(CRT_PATH + "login.live.com.crt"), "31:AE:F1:7C:98:67:E9:1F:19:69:A2:A7:84:1E:67:5C:AA:C3:6B:75", }, }; } @DataProvider(name = "authority-keyid") public Object[][] getAuthorityKeyId() throws Exception { return new Object[][] { new Object[] { CertUtil.readCertificate(CRT_PATH + "serac-dev-test.crt"), "38:E0:6F:AE:48:ED:5E:23:F6:22:9B:1E:E7:9C:19:16:47:B8:7E:92", }, new Object[] { CertUtil.readCertificate(CRT_PATH + "login.live.com.crt"), "FC:8A:50:BA:9E:B9:25:5A:7B:55:85:4F:95:00:63:8F:E9:58:6B:43", }, }; } @DataProvider(name = "cert-chains") public Object[][] getCertificateChains() throws Exception { return new Object[][] { {CRT_PATH + "vtgsca_chain.pem", 4}, {CRT_PATH + "vtuca_chain.p7b", 2}, }; } @Test(dataProvider = "subject-cn") public void testSubjectCN(final X509Certificate cert, final String expected) { assertEquals(CertUtil.subjectCN(cert), expected); } @Test(dataProvider = "subject-alt-names") public void testSubjectAltNames(final X509Certificate cert, final String[] expected) throws Exception { final GeneralNames names = CertUtil.subjectAltNames(cert); if (expected.length == 0) { assertNull(names); return; } assertEquals(names.getNames().length, expected.length); for (int i = 0; i < expected.length; i++) { assertEquals(names.getNames()[i].getName().toString(), expected[i]); } } @Test(dataProvider = "subject-alt-names-by-type") public void testSubjectAltNamesByType( final X509Certificate cert, final GeneralNameType[] types, final String[] expected) throws Exception { final GeneralNames names = CertUtil.subjectAltNames(cert, types); if (expected.length == 0) { assertNull(names); return; } assertEquals(names.getNames().length, expected.length); for (int i = 0; i < expected.length; i++) { assertEquals(names.getNames()[i].getName().toString(), expected[i]); } } @Test(dataProvider = "subject-names") public void testSubjectNames(final X509Certificate cert, final String[] expected) throws Exception { final List names = CertUtil.subjectNames(cert); assertEquals(names.size(), expected.length); for (int i = 0; i < expected.length; i++) { assertEquals(names.get(i), expected[i]); } } @Test(dataProvider = "subject-names-by-type") public void testSubjectNamesByType(final X509Certificate cert, final GeneralNameType[] types, final String[] expected) throws Exception { final List names = CertUtil.subjectNames(cert, types); assertEquals(names.size(), expected.length); for (int i = 0; i < expected.length; i++) { assertEquals(names.get(i), expected[i]); } } @Test(dataProvider = "entity-certificate") public void testFindEntityCertificate( final PrivateKey key, final X509Certificate[] candidates, final X509Certificate expected) throws Exception { assertEquals(CertUtil.findEntityCertificate(key, candidates), expected); } @Test(dataProvider = "basic-usage") public void testAllowsBasicUsage(final X509Certificate cert, final KeyUsageBits[] expectedUses) throws Exception { assertTrue(CertUtil.allowsUsage(cert, expectedUses)); } @Test(dataProvider = "extended-usage") public void testAllowsExtendedUsage(final X509Certificate cert, final KeyPurposeId[] expectedPurposes) throws Exception { assertTrue(CertUtil.allowsUsage(cert, expectedPurposes)); } @Test(dataProvider = "has-policies") public void testHasPolicies(final X509Certificate cert, final String[] expectedPolicies) throws Exception { assertTrue(CertUtil.hasPolicies(cert, expectedPolicies)); } @Test(dataProvider = "subject-keyid") public void testSubjectKeyId(final X509Certificate cert, final String expectedKeyId) throws Exception { assertEquals(CertUtil.subjectKeyId(cert).toUpperCase(), expectedKeyId); } @Test(dataProvider = "authority-keyid") public void testAuthorityKeyId(final X509Certificate cert, final String expectedKeyId) throws Exception { assertEquals(CertUtil.authorityKeyId(cert).toUpperCase(), expectedKeyId); } @Test(dataProvider = "cert-chains") public void testReadCertificateChains(final String path, final int expectedCount) throws Exception { assertEquals(CertUtil.readCertificateChain(path).length, expectedCount); } } cryptacular-1.2.5/src/test/java/org/cryptacular/util/CipherUtilTest.java000066400000000000000000000204041422604312300264040ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.util; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import javax.crypto.SecretKey; import org.bouncycastle.crypto.BlockCipher; import org.bouncycastle.crypto.engines.AESEngine; import org.bouncycastle.crypto.engines.BlowfishEngine; import org.bouncycastle.crypto.engines.TwofishEngine; import org.bouncycastle.crypto.modes.AEADBlockCipher; import org.bouncycastle.crypto.modes.CBCBlockCipher; import org.bouncycastle.crypto.modes.CCMBlockCipher; import org.bouncycastle.crypto.modes.CFBBlockCipher; import org.bouncycastle.crypto.modes.GCMBlockCipher; import org.bouncycastle.crypto.modes.OCBBlockCipher; import org.bouncycastle.crypto.modes.OFBBlockCipher; import org.cryptacular.FailListener; import org.cryptacular.bean.KeyStoreBasedKeyFactoryBean; import org.cryptacular.bean.KeyStoreFactoryBean; import org.cryptacular.generator.Nonce; import org.cryptacular.generator.SecretKeyGenerator; import org.cryptacular.generator.sp80038a.LongCounterNonce; import org.cryptacular.generator.sp80038a.RBGNonce; import org.cryptacular.generator.sp80038d.CounterNonce; import org.cryptacular.io.FileResource; import org.testng.annotations.DataProvider; import org.testng.annotations.Listeners; import org.testng.annotations.Test; import static org.testng.Assert.assertEquals; /** * Unit test for {@link CipherUtil} class. * * @author Middleware Services */ @Listeners(FailListener.class) public class CipherUtilTest { /** Static key derived from keystore on resource classpath. */ private static final SecretKey STATIC_KEY; static { final KeyStoreFactoryBean keyStoreFactory = new KeyStoreFactoryBean(); keyStoreFactory.setPassword("vtcrypt"); keyStoreFactory.setResource(new FileResource(new File("src/test/resources/keystores/cipher-bean.jceks"))); keyStoreFactory.setType("JCEKS"); final KeyStoreBasedKeyFactoryBean keyFactory = new KeyStoreBasedKeyFactoryBean<>(); keyFactory.setKeyStore(keyStoreFactory.newInstance()); keyFactory.setAlias("vtcrypt"); keyFactory.setPassword("vtcrypt"); STATIC_KEY = keyFactory.newInstance(); } @DataProvider(name = "block-cipher") public Object[][] getBlockCipherData() { return new Object[][] { new Object[] { // Plaintext is NOT multiple of block size "Able was I ere I saw elba.", new CBCBlockCipher(new AESEngine()), new RBGNonce(16), }, // Plaintext is multiple of block size new Object[] { "Four score and seven years ago, our forefathers ", new CBCBlockCipher(new BlowfishEngine()), new RBGNonce(8), }, // OFB new Object[] { "Have you passed through this night?", new OFBBlockCipher(new BlowfishEngine(), 64), new LongCounterNonce(), }, // CFB new Object[] { "I went to the woods because I wished to live deliberately, to front only the essential facts of life", new CFBBlockCipher(new AESEngine(), 128), new RBGNonce(16), }, }; } @DataProvider(name = "aead-block-cipher") public Object[][] getAeadBlockCipherData() { return new Object[][] { new Object[] { // Plaintext is NOT multiple of block size "I never picked cotton like my mother did", new GCMBlockCipher(new AESEngine()), }, new Object[] { // Plaintext is multiple of block size "Cogito ergo sum.", new GCMBlockCipher(new AESEngine()), }, // CCM new Object[] { "Thousands of candles can be lit from a single candle and the life of the candle will not be shortened.", new CCMBlockCipher(new TwofishEngine()), }, // OCB new Object[] { "I slept and dreamt life was joy. I awoke and saw that life was service. " + "I acted and behold: service was joy.", new OCBBlockCipher(new AESEngine(), new AESEngine()), }, }; } @DataProvider(name = "plaintext-files") public Object[][] getPlaintextFiles() { return new Object[][] { new Object[] {"src/test/resources/plaintexts/lorem-1200.txt"}, new Object[] {"src/test/resources/plaintexts/lorem-5000.txt"}, }; } @Test(dataProvider = "block-cipher") public void testBlockCipherEncryptDecrypt(final String plaintext, final BlockCipher cipher, final Nonce nonce) { final SecretKey key = SecretKeyGenerator.generate(cipher); final byte[] ciphertext = CipherUtil.encrypt(cipher, key, nonce, plaintext.getBytes()); final byte[] result = CipherUtil.decrypt(cipher, key, ciphertext); assertEquals(new String(result), plaintext); } @Test(dataProvider = "aead-block-cipher") public void testAeadBlockCipherEncryptDecrypt(final String plaintext, final AEADBlockCipher cipher) { final BlockCipher under = cipher.getUnderlyingCipher(); final SecretKey key = SecretKeyGenerator.generate(under); final byte[] ciphertext = CipherUtil.encrypt(cipher, key, new RBGNonce(12), plaintext.getBytes()); final byte[] result = CipherUtil.decrypt(cipher, key, ciphertext); assertEquals(new String(result), plaintext); } @Test(dataProvider = "plaintext-files") public void testBlockCipherEncryptDecryptStream(final String path) throws Exception { final BlockCipher cipher = new CBCBlockCipher(new AESEngine()); final SecretKey key = SecretKeyGenerator.generate(cipher); final Nonce nonce = new CounterNonce("vt-crypt", 1); final File file = new File(path); final String expected = new String(StreamUtil.readAll(file)); final ByteArrayOutputStream tempOut = new ByteArrayOutputStream(); CipherUtil.encrypt(cipher, key, nonce, StreamUtil.makeStream(file), tempOut); final ByteArrayInputStream tempIn = new ByteArrayInputStream(tempOut.toByteArray()); final ByteArrayOutputStream actual = new ByteArrayOutputStream(); CipherUtil.decrypt(cipher, key, tempIn, actual); assertEquals(new String(actual.toByteArray()), expected); } @Test(dataProvider = "plaintext-files") public void testAeadBlockCipherEncryptDecryptStream(final String path) throws Exception { final AEADBlockCipher cipher = new GCMBlockCipher(new AESEngine()); final SecretKey key = SecretKeyGenerator.generate(cipher.getUnderlyingCipher()); final File file = new File(path); final String expected = new String(StreamUtil.readAll(file)); final ByteArrayOutputStream tempOut = new ByteArrayOutputStream(); CipherUtil.encrypt(cipher, key, new RBGNonce(), StreamUtil.makeStream(file), tempOut); final ByteArrayInputStream tempIn = new ByteArrayInputStream(tempOut.toByteArray()); final ByteArrayOutputStream actual = new ByteArrayOutputStream(); CipherUtil.decrypt(cipher, key, tempIn, actual); assertEquals(new String(actual.toByteArray()), expected); } @Test public void testDecryptArrayBackwardCompatibleHeader() { final AEADBlockCipher cipher = new OCBBlockCipher(new TwofishEngine(), new TwofishEngine()); final String expected = "Have you passed through this night?"; final String v1CiphertextHex = "0000001f0000000c76746d770002ba17043672d900000007767463727970745a38dee735266e3f5f7aafec8d1c9ed8a0830a2ff9" + "c3a46c25f89e69b6eb39dbb82fd13da50e32b2544a73f1a4476677b377e6"; final byte[] plaintext = CipherUtil.decrypt(cipher, STATIC_KEY, CodecUtil.hex(v1CiphertextHex)); assertEquals(expected, ByteUtil.toString(plaintext)); } @Test public void testDecryptStreamBackwardCompatibleHeader() { final AEADBlockCipher cipher = new OCBBlockCipher(new TwofishEngine(), new TwofishEngine()); final String expected = "Have you passed through this night?"; final String v1CiphertextHex = "0000001f0000000c76746d770002ba17043672d900000007767463727970745a38dee735266e3f5f7aafec8d1c9ed8a0830a2ff9" + "c3a46c25f89e69b6eb39dbb82fd13da50e32b2544a73f1a4476677b377e6"; final ByteArrayInputStream in = new ByteArrayInputStream(CodecUtil.hex(v1CiphertextHex)); final ByteArrayOutputStream out = new ByteArrayOutputStream(); CipherUtil.decrypt(cipher, STATIC_KEY, in, out); assertEquals(expected, ByteUtil.toString(out.toByteArray())); } } cryptacular-1.2.5/src/test/java/org/cryptacular/util/HashUtilTest.java000066400000000000000000000075651422604312300260720ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.util; import java.io.File; import java.io.InputStream; import org.bouncycastle.crypto.Digest; import org.bouncycastle.crypto.digests.SHA1Digest; import org.bouncycastle.crypto.digests.SHA256Digest; import org.bouncycastle.util.encoders.Hex; import org.cryptacular.FailListener; import org.cryptacular.SaltedHash; import org.testng.annotations.DataProvider; import org.testng.annotations.Listeners; import org.testng.annotations.Test; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertTrue; /** * Unit test for {@link HashUtil}. * * @author Middleware Services */ @Listeners(FailListener.class) public class HashUtilTest { private static final byte[] SALT = new byte[] {0, 1, 2, 3, 4, 5, 6, 7}; @DataProvider(name = "salted-hashes") public Object[][] getSaltedHashData() { return new Object[][] { { new SHA1Digest(), new Object[] {ByteUtil.toBytes("deoxyribonucleic acid"), }, 1, "0aDM5g/qqfVV/8MIqkTKQaklWSg=", }, { new SHA1Digest(), new Object[] { ByteUtil.toBytes("protoporphyrin-9"), SALT, }, 1, "6SafHIoTusYN6dnK1pxx7udaBLA=", }, { new SHA256Digest(), new Object[] { SALT, ByteUtil.toBytes("N-arachidonoylethanolamine"), }, 5, "RWIg3BIXdqZPI9C7PFvSn62miU3L9ponVZLvKmC9XlQ=", }, }; } @DataProvider(name = "hash-compare") public Object[][] getHashCompareData() { return new Object[][] { { new SHA1Digest(), CodecUtil.b64("7fyOZXGp+gKMziV/2Px7RIMkxyI2O1H8"), 1, ByteUtil.toBytes("password"), }, { new SHA1Digest(), CodecUtil.b64("0aDM5g/qqfVV/8MIqkTKQaklWSg="), 1, ByteUtil.toBytes("deoxyribonucleic acid"), }, }; } @DataProvider(name = "salted-hash-compare") public Object[][] getSaltedHashCompareData() { return new Object[][] { { new SHA1Digest(), new SaltedHash(CodecUtil.b64("7fyOZXGp+gKMziV/2Px7RIMkxyI2O1H8"), 20, true), 1, true, ByteUtil.toBytes("password"), }, }; } @DataProvider(name = "file-hashes") public Object[][] getFileHashes() { return new Object[][] { new Object[] { "src/test/resources/plaintexts/lorem-1200.txt", "f0746e8978b3eccca05284dd12f098fdea32c8bc", }, new Object[] { "src/test/resources/plaintexts/lorem-5000.txt", "1142d7a2661760624fa41b002be6c66c23b50602", }, }; } @Test(dataProvider = "salted-hashes") public void testSaltedHash(final Digest digest, final Object[] data, final int iterations, final String expected) throws Exception { assertEquals(CodecUtil.b64(HashUtil.hash(digest, iterations, data)), expected); } @Test(dataProvider = "hash-compare") public void testCompareHash(final Digest digest, final byte[] hash, final int iterations, final byte[] data) throws Exception { assertTrue(HashUtil.compareHash(digest, hash, iterations, data)); } @Test(dataProvider = "salted-hash-compare") public void testCompareSaltedHash( final Digest digest, final SaltedHash saltedHash, final int iterations, final boolean saltAfterData, final byte[] data) throws Exception { assertTrue(HashUtil.compareHash(digest, saltedHash, iterations, saltAfterData, data)); } @Test(dataProvider = "file-hashes") public void testHashStream(final String path, final String expected) throws Exception { try (InputStream in = StreamUtil.makeStream(new File(path))) { assertEquals(Hex.toHexString(HashUtil.sha1(in)), expected); } } } cryptacular-1.2.5/src/test/java/org/cryptacular/util/KeyPairUtilTest.java000066400000000000000000000321761422604312300265470ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.util; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.security.KeyPair; import java.security.PrivateKey; import java.security.PublicKey; import java.security.SecureRandom; import java.security.interfaces.DSAPrivateKey; import java.security.interfaces.DSAPublicKey; import java.security.interfaces.ECPrivateKey; import java.security.interfaces.ECPublicKey; import java.security.interfaces.RSAPrivateCrtKey; import java.security.interfaces.RSAPublicKey; import org.cryptacular.FailListener; import org.cryptacular.generator.KeyPairGenerator; import org.testng.annotations.DataProvider; import org.testng.annotations.Listeners; import org.testng.annotations.Test; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertNotNull; import static org.testng.Assert.assertTrue; /** * Unit test for {@link KeyPairUtil} class. * * @author Middleware Services */ @Listeners(FailListener.class) public class KeyPairUtilTest { private static final String KEY_PATH = "src/test/resources/keys/"; private final SecureRandom random = new SecureRandom(); private final KeyPair rsa512 = KeyPairGenerator.generateRSA(random, 512); private final KeyPair dsa1024 = KeyPairGenerator.generateDSA(random, 1024); private final KeyPair ec256 = KeyPairGenerator.generateEC(random, 256); private final KeyPair ec224 = KeyPairGenerator.generateEC(random, "P-224"); @DataProvider(name = "public-keys") public Object[][] getPublicKeys() { return new Object[][] { new Object[] {dsa1024.getPublic(), 1024}, new Object[] {rsa512.getPublic(), 512}, new Object[] {ec256.getPublic(), 256}, }; } @DataProvider(name = "private-keys") public Object[][] getPrivateKeys() { return new Object[][] { new Object[] {dsa1024.getPrivate(), 160}, new Object[] {rsa512.getPrivate(), 512}, new Object[] {ec224.getPrivate(), 224}, }; } @DataProvider(name = "key-pairs") public Object[][] getKeyPairs() { final KeyPair rsa512p2 = KeyPairGenerator.generateRSA(random, 512); return new Object[][] { new Object[] {rsa512.getPublic(), rsa512.getPrivate(), true}, new Object[] {rsa512p2.getPublic(), rsa512p2.getPrivate(), true}, new Object[] {rsa512.getPublic(), rsa512p2.getPrivate(), false}, new Object[] {ec256.getPublic(), ec256.getPrivate(), true}, new Object[] {ec224.getPublic(), ec224.getPrivate(), true}, new Object[] { KeyPairUtil.readPublicKey(KEY_PATH + "ec-openssl-prime256v1-named-pub.pem"), KeyPairUtil.readPrivateKey(KEY_PATH + "ec-openssl-prime256v1-named-nopass.pem"), true, }, new Object[] { KeyPairUtil.readPublicKey(KEY_PATH + "ec-openssl-secp112r1-named-pub.pem"), KeyPairUtil.readPrivateKey(KEY_PATH + "ec-openssl-secp112r1-named-nopass.pem"), true, }, new Object[] { KeyPairUtil.readPublicKey(KEY_PATH + "ec-openssl-secp224k1-explicit-pub.pem"), KeyPairUtil.readPrivateKey(KEY_PATH + "ec-openssl-secp224k1-explicit-nopass.pem"), true, }, new Object[] { KeyPairUtil.readPublicKey(KEY_PATH + "ec-openssl-secp256k1-explicit-pub.pem"), KeyPairUtil.readPrivateKey(KEY_PATH + "ec-openssl-secp256k1-explicit-nopass.pem"), true, }, new Object[] { KeyPairUtil.readPublicKey(KEY_PATH + "ec-openssl-sect409k1-named-pub.pem"), KeyPairUtil.readPrivateKey(KEY_PATH + "ec-openssl-sect409k1-named-nopass.pem"), true, }, new Object[] { KeyPairUtil.readPublicKey(KEY_PATH + "ec-openssl-sect571r1-explicit-pub.pem"), KeyPairUtil.readPrivateKey(KEY_PATH + "ec-openssl-sect571r1-explicit-nopass.pem"), true, }, new Object[] { KeyPairUtil.readPublicKey(KEY_PATH + "ec-openssl-sect571r1-explicit-pub.pem"), KeyPairUtil.readPrivateKey(KEY_PATH + "ec-openssl-sect571r1-explicit-nopass.pem"), true, }, }; } @DataProvider(name = "private-key-files") public Object[][] getPrivateKeyFiles() { return new Object[][] { new Object[] {KEY_PATH + "dsa-openssl-nopass.der", DSAPrivateKey.class}, new Object[] {KEY_PATH + "dsa-openssl-nopass.pem", DSAPrivateKey.class}, new Object[] { KEY_PATH + "rsa-openssl-nopass.der", RSAPrivateCrtKey.class, }, new Object[] { KEY_PATH + "rsa-openssl-nopass.pem", RSAPrivateCrtKey.class, }, new Object[] { KEY_PATH + "ec-openssl-prime256v1-named-nopass.der", ECPrivateKey.class, }, new Object[] { KEY_PATH + "ec-openssl-prime256v1-named-nopass.pem", ECPrivateKey.class, }, new Object[] { KEY_PATH + "ec-openssl-secp112r1-named-nopass.der", ECPrivateKey.class, }, new Object[] { KEY_PATH + "ec-openssl-secp112r1-named-nopass.pem", ECPrivateKey.class, }, new Object[] { KEY_PATH + "ec-openssl-secp224k1-explicit-nopass.der", ECPrivateKey.class, }, new Object[] { KEY_PATH + "ec-openssl-secp224k1-explicit-nopass.pem", ECPrivateKey.class, }, new Object[] { KEY_PATH + "ec-openssl-sect571r1-explicit-nopass.der", ECPrivateKey.class, }, new Object[] { KEY_PATH + "ec-openssl-sect571r1-explicit-nopass.pem", ECPrivateKey.class, }, new Object[] {KEY_PATH + "dsa-pkcs8-nopass.der", DSAPrivateKey.class}, new Object[] {KEY_PATH + "dsa-pkcs8-nopass.pem", DSAPrivateKey.class}, new Object[] { KEY_PATH + "rsa-pkcs8-nopass.der", RSAPrivateCrtKey.class, }, new Object[] { KEY_PATH + "rsa-pkcs8-nopass.pem", RSAPrivateCrtKey.class, }, new Object[] { KEY_PATH + "rsa-pkcs8-nopass-noheader.pem", RSAPrivateCrtKey.class, }, new Object[] { KEY_PATH + "ec-pkcs8-secp224k1-explicit-nopass.der", ECPrivateKey.class, }, new Object[] { KEY_PATH + "ec-pkcs8-secp224k1-explicit-nopass.pem", ECPrivateKey.class, }, }; } @DataProvider(name = "encrypted-private-key-files") public Object[][] getEncryptedPrivateKeyFiles() { return new Object[][] { new Object[] { KEY_PATH + "dsa-openssl-des3.pem", "vtcrypt", DSAPrivateKey.class, }, new Object[] { KEY_PATH + "rsa-openssl-des.pem", "vtcrypt", RSAPrivateCrtKey.class, }, new Object[] { KEY_PATH + "rsa-openssl-des-noheader.pem", "vtcrypt", RSAPrivateCrtKey.class, }, new Object[] { KEY_PATH + "rsa-openssl-des3.pem", "vtcrypt", RSAPrivateCrtKey.class, }, new Object[] { KEY_PATH + "ec-openssl-secp224k1-explicit-des.pem", "vtcrypt", ECPrivateKey.class, }, new Object[] { KEY_PATH + "ec-openssl-sect571r1-explicit-des.pem", "vtcrypt", ECPrivateKey.class, }, new Object[] { KEY_PATH + "dsa-pkcs8-priv.der", "vtcrypt", DSAPrivateKey.class, }, new Object[] { KEY_PATH + "dsa-pkcs8-priv.pem", "vtcrypt", DSAPrivateKey.class, }, new Object[] { KEY_PATH + "dsa-pkcs8-v2-des3.der", "vtcrypt", DSAPrivateKey.class, }, new Object[] { KEY_PATH + "dsa-pkcs8-v2-des3.pem", "vtcrypt", DSAPrivateKey.class, }, new Object[] { KEY_PATH + "rsa-pkcs8-v1-md5-des.der", "vtcrypt", RSAPrivateCrtKey.class, }, new Object[] { KEY_PATH + "rsa-pkcs8-v1-md5-des.pem", "vtcrypt", RSAPrivateCrtKey.class, }, new Object[] { KEY_PATH + "rsa-pkcs8-v1-md5-rc2-64.der", "vtcrypt", RSAPrivateCrtKey.class, }, new Object[] { KEY_PATH + "rsa-pkcs8-v2-aes256.der", "vtcrypt", RSAPrivateCrtKey.class, }, new Object[] { KEY_PATH + "rsa-pkcs8-v2-aes256.pem", "vtcrypt", RSAPrivateCrtKey.class, }, new Object[] { KEY_PATH + "rsa-pkcs8-v2-aes256-noheader.pem", "vtcrypt", RSAPrivateCrtKey.class, }, new Object[] { KEY_PATH + "ec-pkcs8-secp224k1-explicit-sha1-rc4-128.der", "vtcrypt", ECPrivateKey.class, }, new Object[] { KEY_PATH + "ec-pkcs8-secp224k1-explicit-v1-sha1-rc2-64.der", "vtcrypt", ECPrivateKey.class, }, new Object[] { KEY_PATH + "ec-pkcs8-secp224k1-explicit-v2-des3.pem", "vtcrypt", ECPrivateKey.class, }, new Object[] { KEY_PATH + "ec-pkcs8-sect571r1-explicit-v2-aes128.pem", "vtcrypt", ECPrivateKey.class, }, new Object[] { KEY_PATH + "ec-pkcs8-sect571r1-named-v1-sha1-rc2-64.der", "vtcrypt", ECPrivateKey.class, }, }; } @DataProvider(name = "public-key-files") public Object[][] getPublicKeyFiles() { return new Object[][] { new Object[] {KEY_PATH + "dsa-pub.der", DSAPublicKey.class}, new Object[] {KEY_PATH + "dsa-pub.pem", DSAPublicKey.class}, new Object[] { KEY_PATH + "ec-secp224k1-explicit-pub.der", ECPublicKey.class, }, new Object[] { KEY_PATH + "ec-secp224k1-explicit-pub.pem", ECPublicKey.class, }, new Object[] {KEY_PATH + "rsa-pub.der", RSAPublicKey.class}, new Object[] {KEY_PATH + "rsa-pub.pem", RSAPublicKey.class}, }; } @Test(dataProvider = "public-keys") public void testLengthPublicKey(final PublicKey key, final int expectedLength) throws Exception { assertEquals(KeyPairUtil.length(key), expectedLength); } @Test(dataProvider = "private-keys") public void testLengthPrivateKey(final PrivateKey key, final int expectedLength) throws Exception { assertEquals(KeyPairUtil.length(key), expectedLength); } @Test(dataProvider = "key-pairs") public void testIsKeyPair(final PublicKey pubKey, final PrivateKey privKey, final boolean expected) throws Exception { assertEquals(KeyPairUtil.isKeyPair(pubKey, privKey), expected); } @Test(dataProvider = "private-key-files") public void testReadPrivateKey(final String path, final Class expectedType) throws Exception { final PrivateKey key = KeyPairUtil.readPrivateKey(path); assertNotNull(key); assertTrue(expectedType.isAssignableFrom(key.getClass())); } @Test(dataProvider = "encrypted-private-key-files") public void testReadEncryptedPrivateKey(final String path, final String password, final Class expectedType) throws Exception { final PrivateKey key = KeyPairUtil.readPrivateKey(path, password.toCharArray()); assertNotNull(key); assertTrue(expectedType.isAssignableFrom(key.getClass())); } @Test(dataProvider = "public-key-files") public void testReadPublicKey(final String path, final Class expectedType) throws Exception { final PublicKey key = KeyPairUtil.readPublicKey(path); assertNotNull(key); assertTrue(expectedType.isAssignableFrom(key.getClass())); } @Test(dataProvider = "private-key-files") public void testClosePrivateKey(final String path, final Class expectedType) throws Exception { final TestableFileInputStream is = new TestableFileInputStream(path); final PrivateKey key = KeyPairUtil.readPrivateKey(is); assertNotNull(key); assertTrue(is.isClosed()); } @Test(dataProvider = "public-key-files") public void testClosePublicKey(final String path, final Class expectedType) throws Exception { final TestableFileInputStream is = new TestableFileInputStream(path); final PublicKey key = KeyPairUtil.readPublicKey(is); assertNotNull(key); assertTrue(is.isClosed()); } /** * Class for testing usage of {@link FileInputStream}. */ private class TestableFileInputStream extends FileInputStream { /** Whether {@link #close()} has been invoked. */ private boolean isClosed; /** * Default constructor. * * @param name of the file to open * * @throws FileNotFoundException if an error occurs */ TestableFileInputStream(final String name) throws FileNotFoundException { super(name); } @Override public void close() throws IOException { super.close(); isClosed = true; } /** * Returns whether {@link #close()} has been invoked. * * @return whether {@link #close()} has been invoked */ public boolean isClosed() { return isClosed; } } } cryptacular-1.2.5/src/test/java/org/cryptacular/x509/000077500000000000000000000000001422604312300223615ustar00rootroot00000000000000cryptacular-1.2.5/src/test/java/org/cryptacular/x509/ExtensionReaderTest.java000066400000000000000000000275071422604312300271760ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.x509; import java.security.cert.X509Certificate; import java.util.List; import org.bouncycastle.asn1.ASN1ObjectIdentifier; import org.bouncycastle.asn1.DERSequence; import org.bouncycastle.asn1.x509.AccessDescription; import org.bouncycastle.asn1.x509.AuthorityKeyIdentifier; import org.bouncycastle.asn1.x509.DistributionPoint; import org.bouncycastle.asn1.x509.DistributionPointName; import org.bouncycastle.asn1.x509.GeneralName; import org.bouncycastle.asn1.x509.GeneralNames; import org.bouncycastle.asn1.x509.KeyPurposeId; import org.bouncycastle.asn1.x509.KeyUsage; import org.bouncycastle.asn1.x509.PolicyInformation; import org.bouncycastle.asn1.x509.PolicyQualifierInfo; import org.bouncycastle.asn1.x509.SubjectKeyIdentifier; import org.cryptacular.FailListener; import org.cryptacular.util.CertUtil; import org.cryptacular.util.CodecUtil; import org.testng.annotations.DataProvider; import org.testng.annotations.Listeners; import org.testng.annotations.Test; import static org.testng.Assert.assertEquals; /** * Unit test for {@link ExtensionReader}. * * @author Middleware Services */ @Listeners(FailListener.class) public class ExtensionReaderTest { private static final String CRT_PATH = "src/test/resources/certs/"; @DataProvider(name = "subject-alt-name") public Object[][] getSubjectAltNames() { return new Object[][] { new Object[] { CertUtil.readCertificate(CRT_PATH + "serac-dev-test.crt"), new String[] {"eprov@vt.edu"}, }, new Object[] { CertUtil.readCertificate(CRT_PATH + "ed.middleware.vt.edu.crt"), new String[] { "ed.middleware.vt.edu", "directory.vt.edu", "id.directory.vt.edu", "authn.directory.vt.edu", "ldap.vt.edu", }, }, }; } @DataProvider(name = "issuer-alt-name") public Object[][] getIssuerAltNames() { return new Object[][] { new Object[] { CertUtil.readCertificate(CRT_PATH + "test.example.com.crt"), new String[] {"snake-1.example.com", "snake-2.example.com"}, }, }; } @DataProvider(name = "basic-constraints") public Object[][] getBasicConstraints() { return new Object[][] { new Object[] { CertUtil.readCertificate(CRT_PATH + "thawte-premium-server-ca.crt"), true, }, new Object[] { CertUtil.readCertificate(CRT_PATH + "login.live.com.crt"), false, }, }; } @DataProvider(name = "certificate-policies") public Object[][] getCertificatePolicies() { return new Object[][] { new Object[] { CertUtil.readCertificate(CRT_PATH + "serac-dev-test.crt"), new PolicyInformation[] { new PolicyInformation(new ASN1ObjectIdentifier("1.3.6.1.4.1.6760.5.2.2.2.1")), new PolicyInformation(new ASN1ObjectIdentifier("1.3.6.1.4.1.6760.5.2.2.1.1")), new PolicyInformation( new ASN1ObjectIdentifier("1.3.6.1.4.1.6760.5.2.2.4.1"), new DERSequence(new PolicyQualifierInfo("http://www.pki.vt.edu/vtuca/cps/index.html"))), new PolicyInformation(new ASN1ObjectIdentifier("1.3.6.1.4.1.6760.5.2.2.3.1")), }, }, }; } @DataProvider(name = "subject-key-id") public Object[][] getSubjectKeyIds() { return new Object[][] { new Object[] { CertUtil.readCertificate(CRT_PATH + "serac-dev-test.crt"), "25:48:2F:28:EC:5D:19:BB:1D:25:AE:94:93:B1:7B:B5:35:96:24:66", }, new Object[] { CertUtil.readCertificate(CRT_PATH + "login.live.com.crt"), "31:AE:F1:7C:98:67:E9:1F:19:69:A2:A7:84:1E:67:5C:AA:C3:6B:75", }, }; } @DataProvider(name = "authority-key-id") public Object[][] getAuthorityKeyIds() { return new Object[][] { new Object[] { CertUtil.readCertificate(CRT_PATH + "serac-dev-test.crt"), "38:E0:6F:AE:48:ED:5E:23:F6:22:9B:1E:E7:9C:19:16:47:B8:7E:92", }, new Object[] { CertUtil.readCertificate(CRT_PATH + "login.live.com.crt"), "FC:8A:50:BA:9E:B9:25:5A:7B:55:85:4F:95:00:63:8F:E9:58:6B:43", }, }; } @DataProvider(name = "key-usage") public Object[][] getKeyUsage() { return new Object[][] { new Object[] { CertUtil.readCertificate(CRT_PATH + "serac-dev-test.crt"), KeyUsageBits.usage(KeyUsageBits.DigitalSignature, KeyUsageBits.NonRepudiation), }, new Object[] { CertUtil.readCertificate(CRT_PATH + "login.live.com.crt"), KeyUsageBits.usage(KeyUsageBits.DigitalSignature, KeyUsageBits.KeyEncipherment), }, }; } @DataProvider(name = "extended-key-usage") public Object[][] getExtendedKeyUsage() { return new Object[][] { new Object[] { CertUtil.readCertificate(CRT_PATH + "serac-dev-test.crt"), new KeyPurposeId[] { KeyPurposeId.id_kp_clientAuth, KeyPurposeId.id_kp_emailProtection, KeyPurposeId.id_kp_smartcardlogon, }, }, new Object[] { CertUtil.readCertificate(CRT_PATH + "login.live.com.crt"), new KeyPurposeId[] { KeyPurposeId.id_kp_serverAuth, KeyPurposeId.id_kp_clientAuth, }, }, }; } @DataProvider(name = "crl-distribution-points") public Object[][] getCrlDistributionPoints() { return new Object[][] { new Object[] { CertUtil.readCertificate(CRT_PATH + "login.live.com.crt"), new DistributionPoint[] { new DistributionPoint( new DistributionPointName(new GeneralNames(uri("http://EVSecure-crl.verisign.com/EVSecure2006.crl"))), null, null), }, }, new Object[] { CertUtil.readCertificate(CRT_PATH + "glider.cc.vt.edu.crt"), new DistributionPoint[] { new DistributionPoint( new DistributionPointName( new GeneralNames( uri( "http://vtca-p.eprov.seti.vt.edu:8080/ejbca/publicweb/" + "webdist/certdist?cmd=crl&" + "issuer=CN=Virginia+Tech+Middleware+CA,O=Virginia+" + "Polytechnic+Institute+and+State+University," + "DC=vt,DC=edu,C=US"))), null, new GeneralNames( dirName( "CN=Virginia Tech Middleware CA,O=Virginia Polytechnic " + "Institute and State University,DC=vt,DC=edu,C=US"))), }, }, }; } @DataProvider(name = "authority-information-access") public Object[][] getAuthorityInformationAccess() { return new Object[][] { new Object[] { CertUtil.readCertificate(CRT_PATH + "login.live.com.crt"), new AccessDescription[] { new AccessDescription(AccessDescription.id_ad_ocsp, uri("http://EVSecure-ocsp.verisign.com")), new AccessDescription( AccessDescription.id_ad_caIssuers, uri("http://EVSecure-aia.verisign.com/EVSecure2006.cer")), }, }, }; } @Test(dataProvider = "subject-alt-name") public void testReadSubjectAlternativeName(final X509Certificate cert, final String[] expected) throws Exception { final GeneralNames names = new ExtensionReader(cert).readSubjectAlternativeName(); assertEquals(names.getNames().length, expected.length); for (int i = 0; i < expected.length; i++) { assertEquals(names.getNames()[i].getName().toString(), expected[i]); } } @Test(dataProvider = "issuer-alt-name") public void testReadIssuerAlternativeName(final X509Certificate cert, final String[] expected) throws Exception { final GeneralNames names = new ExtensionReader(cert).readIssuerAlternativeName(); assertEquals(names.getNames().length, expected.length); for (int i = 0; i < expected.length; i++) { assertEquals(names.getNames()[i].getName().toString(), expected[i]); } } @Test(dataProvider = "basic-constraints") public void testReadBasicConstraints(final X509Certificate cert, final boolean expected) throws Exception { assertEquals(new ExtensionReader(cert).readBasicConstraints().isCA(), expected); } @Test(dataProvider = "certificate-policies") public void testReadCertificatePolicies(final X509Certificate cert, final PolicyInformation[] expected) throws Exception { final List policies = new ExtensionReader(cert).readCertificatePolicies(); assertEquals(policies.size(), expected.length); PolicyInformation current; for (int i = 0; i < expected.length; i++) { current = policies.get(i); assertEquals(current.getPolicyIdentifier(), expected[i].getPolicyIdentifier()); if (expected[i].getPolicyQualifiers() != null) { for (int j = 0; j < expected[i].getPolicyQualifiers().size(); j++) { assertEquals(current.getPolicyQualifiers().getObjectAt(j), expected[i].getPolicyQualifiers().getObjectAt(j)); } } } } @Test(dataProvider = "subject-key-id") public void testReadSubjectKeyIdentifier(final X509Certificate cert, final String expected) throws Exception { final SubjectKeyIdentifier keyId = new ExtensionReader(cert).readSubjectKeyIdentifier(); assertEquals(CodecUtil.hex(keyId.getKeyIdentifier(), true).toUpperCase(), expected); } @Test(dataProvider = "authority-key-id") public void testReadAuthorityKeyIdentifier(final X509Certificate cert, final String expected) throws Exception { final AuthorityKeyIdentifier keyId = new ExtensionReader(cert).readAuthorityKeyIdentifier(); assertEquals(CodecUtil.hex(keyId.getKeyIdentifier(), true).toUpperCase(), expected); } @Test(dataProvider = "key-usage") public void testReadKeyUsage(final X509Certificate cert, final int expected) throws Exception { final KeyUsage usage = new ExtensionReader(cert).readKeyUsage(); final byte[] bytes = usage.getBytes(); final int result; if (bytes.length == 1) { result = bytes[0] & 0xff; } else { result = (bytes[1] & 0xff) << 8 | (bytes[0] & 0xff); } assertEquals(result, expected); } @Test(dataProvider = "extended-key-usage") public void testReadExtendedKeyUsage(final X509Certificate cert, final KeyPurposeId[] expected) throws Exception { final List purposes = new ExtensionReader(cert).readExtendedKeyUsage(); assertEquals(purposes.size(), expected.length); for (int i = 0; i < expected.length; i++) { assertEquals(purposes.get(i), expected[i]); } } @Test(dataProvider = "crl-distribution-points") public void testReadCRLDistributionPoints(final X509Certificate cert, final DistributionPoint[] expected) throws Exception { final List points = new ExtensionReader(cert).readCRLDistributionPoints(); assertEquals(points.size(), expected.length); for (int i = 0; i < expected.length; i++) { assertEquals(points.get(i), expected[i]); } } @Test(dataProvider = "authority-information-access") public void testReadAuthorityInformationAccess(final X509Certificate cert, final AccessDescription[] expected) throws Exception { final List descriptions = new ExtensionReader(cert).readAuthorityInformationAccess(); assertEquals(descriptions.size(), expected.length); for (int i = 0; i < expected.length; i++) { assertEquals(descriptions.get(i), expected[i]); } } private GeneralName uri(final String uri) { return new GeneralName(GeneralName.uniformResourceIdentifier, uri); } private GeneralName dirName(final String dn) { return new GeneralName(GeneralName.directoryName, dn); } } cryptacular-1.2.5/src/test/java/org/cryptacular/x509/dn/000077500000000000000000000000001422604312300227625ustar00rootroot00000000000000cryptacular-1.2.5/src/test/java/org/cryptacular/x509/dn/LdapNameFormatterTest.java000066400000000000000000000066671422604312300300510ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.x509.dn; import javax.security.auth.x500.X500Principal; import org.cryptacular.FailListener; import org.cryptacular.util.CertUtil; import org.testng.annotations.DataProvider; import org.testng.annotations.Listeners; import org.testng.annotations.Test; import static org.testng.Assert.assertEquals; /** * Unit test for {@link LdapNameFormatter} class. * * @author Middleware Services */ @Listeners(FailListener.class) public class LdapNameFormatterTest { private static final String CRT_PATH = "src/test/resources/certs/"; @DataProvider(name = "distinguished-names") public Object[][] getDistinguishedNames() { return new Object[][] { new Object[] { CertUtil.readCertificate(CRT_PATH + "serac-dev-test.crt").getSubjectX500Principal(), "C=US,DC=vt,DC=edu,O=Virginia Polytechnic Institute and State University,CN=Marvin S Addison,UID=1145718", }, new Object[] { CertUtil.readCertificate(CRT_PATH + "serac-dev-test.crt").getIssuerX500Principal(), "SERIALNUMBER=12,CN=DEV Virginia Tech Class 1 Server CA,O=Virginia " + "Polytechnic Institute and State University,C=US,DC=vt,DC=edu", }, new Object[] { CertUtil.readCertificate(CRT_PATH + "glider.cc.vt.edu.crt").getSubjectX500Principal(), "C=US,DC=edu,DC=vt,ST=Virginia,L=Blacksburg,O=Virginia Polytechnic Institute and State University," + "OU=Middleware-Client,OU=SETI,SERIALNUMBER=1248110657961,CN=glider.cc.vt.edu", }, new Object[] { CertUtil.readCertificate(CRT_PATH + "glider.cc.vt.edu.crt").getIssuerX500Principal(), "CN=Virginia Tech Middleware CA,O=Virginia Polytechnic Institute and State University,C=US,DC=vt,DC=edu", }, new Object[] { CertUtil.readCertificate(CRT_PATH + "multi-value-rdn-1.crt").getSubjectX500Principal(), "CN=b.foo.com,CN=a.foo.com,DC=ldaptive,DC=org", }, new Object[] { CertUtil.readCertificate(CRT_PATH + "multi-value-rdn-2.crt").getSubjectX500Principal(), "DC=org,DC=ldaptive,CN=a.foo.com+CN=b.foo.com", }, new Object[] { CertUtil.readCertificate(CRT_PATH + "needs-escaping-1.crt").getSubjectX500Principal(), "CN=DC=example\\, DC=com,O=VPI&SU,L=Blacksburg,ST=Virginia,C=US,DC=vt,DC=edu", }, new Object[] { CertUtil.readCertificate(CRT_PATH + "needs-escaping-2.crt").getSubjectX500Principal(), "CN=\\#DEADBEEF,O=VPI&SU,L=Blacksburg,ST=Virginia,C=US,DC=vt,DC=edu", }, new Object[] { CertUtil.readCertificate(CRT_PATH + "needs-escaping-3.crt").getSubjectX500Principal(), "CN=\\ space,O=VPI&SU,L=Blacksburg,ST=Virginia,C=US,DC=vt,DC=edu", }, new Object[] { CertUtil.readCertificate(CRT_PATH + "needs-escaping-4.crt").getSubjectX500Principal(), "CN=space2 \\ ,O=VPI&SU,L=Blacksburg,ST=Virginia,C=US,DC=vt,DC=edu", }, new Object[] { CertUtil.readCertificate(CRT_PATH + "unknown-dn-attr.crt").getSubjectX500Principal(), "DC=org,DC=example,1.2.3.4.5=#6e6f6e73656e7365,CN=marzipan", }, }; } @Test(dataProvider = "distinguished-names") public void testFormat(final X500Principal dn, final String expected) throws Exception { assertEquals(new LdapNameFormatter().format(dn), expected); } } cryptacular-1.2.5/src/test/java/org/cryptacular/x509/dn/NameReaderTest.java000066400000000000000000000066101422604312300264730ustar00rootroot00000000000000/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.x509.dn; import java.security.cert.X509Certificate; import org.cryptacular.FailListener; import org.cryptacular.util.CertUtil; import org.testng.annotations.DataProvider; import org.testng.annotations.Listeners; import org.testng.annotations.Test; import static org.testng.Assert.assertEquals; /** * Unit test for {@link NameReader}. * * @author Middleware Services */ @Listeners(FailListener.class) public class NameReaderTest { private static final String CRT_PATH = "src/test/resources/certs/"; @DataProvider(name = "subjects") public Object[][] getSubjects() { return new Object[][] { new Object[] { CertUtil.readCertificate(CRT_PATH + "serac-dev-test.crt"), "UID=1145718, CN=Marvin S Addison, O=Virginia Polytechnic " + "Institute and State University, DC=edu, DC=vt, C=US", }, new Object[] { CertUtil.readCertificate(CRT_PATH + "glider.cc.vt.edu.crt"), "CN=glider.cc.vt.edu, SERIALNUMBER=1248110657961, OU=SETI, " + "OU=Middleware-Client, O=Virginia Polytechnic Institute and " + "State University, L=Blacksburg, ST=Virginia, DC=vt, DC=edu, C=US", }, new Object[] { CertUtil.readCertificate(CRT_PATH + "multi-value-rdn-1.crt"), "DC=org, DC=ldaptive, CN=a.foo.com, CN=b.foo.com", }, new Object[] { CertUtil.readCertificate(CRT_PATH + "multi-value-rdn-2.crt"), "CN=a.foo.com, CN=b.foo.com, DC=ldaptive, DC=org", }, new Object[] { CertUtil.readCertificate(CRT_PATH + "scantor-dn-description.crt"), "DESCRIPTION=6MtpJS1dcC7t254v, CN=cantor.2@osu.edu, EMAILADDRESS=cantor.2@osu.edu", }, new Object[] { CertUtil.readCertificate(CRT_PATH + "unknown-dn-attr.crt"), "CN=marzipan, 1.2.3.4.5=nonsense, DC=example, DC=org", }, }; } @DataProvider(name = "issuers") public Object[][] getIssuers() { return new Object[][] { new Object[] { CertUtil.readCertificate(CRT_PATH + "serac-dev-test.crt"), "DC=edu, DC=vt, C=US, O=Virginia Polytechnic Institute and State " + "University, CN=DEV Virginia Tech Class 1 Server CA, SERIALNUMBER=12", }, new Object[] { CertUtil.readCertificate(CRT_PATH + "glider.cc.vt.edu.crt"), "DC=edu, DC=vt, C=US, O=Virginia Polytechnic Institute and State University, CN=Virginia Tech Middleware CA", }, new Object[] { CertUtil.readCertificate(CRT_PATH + "multi-value-rdn-1.crt"), "DC=org, DC=ldaptive, CN=a.foo.com, CN=b.foo.com", }, new Object[] { CertUtil.readCertificate(CRT_PATH + "multi-value-rdn-2.crt"), "CN=a.foo.com, CN=b.foo.com, DC=ldaptive, DC=org", }, }; } @Test(dataProvider = "subjects") public void testReadSubject(final X509Certificate cert, final String expected) throws Exception { final RDNSequence sequence = new NameReader(cert).readSubject(); assertEquals(sequence.toString(), expected); } @Test(dataProvider = "issuers") public void testReadIssuer(final X509Certificate cert, final String expected) throws Exception { final RDNSequence sequence = new NameReader(cert).readIssuer(); assertEquals(sequence.toString(), expected); } } cryptacular-1.2.5/src/test/resources/000077500000000000000000000000001422604312300176255ustar00rootroot00000000000000cryptacular-1.2.5/src/test/resources/certs/000077500000000000000000000000001422604312300207455ustar00rootroot00000000000000cryptacular-1.2.5/src/test/resources/certs/ed.middleware.vt.edu.crt000066400000000000000000000050411422604312300253670ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIHTjCCBTagAwIBAgIITROLEwW3lyYwDQYJKoZIhvcNAQEFBQAwgZoxEzARBgoJ kiaJk/IsZAEZEwNlZHUxEjAQBgoJkiaJk/IsZAEZEwJ2dDELMAkGA1UEBhMCVVMx PDA6BgNVBAoTM1ZpcmdpbmlhIFBvbHl0ZWNobmljIEluc3RpdHV0ZSBhbmQgU3Rh dGUgVW5pdmVyc2l0eTEkMCIGA1UEAxMbVmlyZ2luaWEgVGVjaCBNaWRkbGV3YXJl IENBMB4XDTEyMDUyNTE2NTMxN1oXDTE0MDUyNTE2NTMxN1owggEAMR0wGwYDVQQD DBRlZC5taWRkbGV3YXJlLnZ0LmVkdTEcMBoGA1UECwwTTWlkZGxld2FyZSBTZXJ2 aWNlczElMCMGA1UECwwcTWlkZGxld2FyZS1TZXJ2ZXItd2l0aC1zYWx0cjE8MDoG A1UECgwzVmlyZ2luaWEgUG9seXRlY2huaWMgSW5zdGl0dXRlIGFuZCBTdGF0ZSBV bml2ZXJzaXR5MRMwEQYDVQQHDApCbGFja3NidXJnMREwDwYDVQQIDAhWaXJnaW5p YTESMBAGCgmSJomT8ixkARkWAnZ0MRMwEQYKCZImiZPyLGQBGRYDZWR1MQswCQYD VQQGEwJVUzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAN2+UJtj+Bhd um+GQe9zciP6nZKBgNWDLPLHo2s+beL0R9n9qIVapqUaB6Rqssgaf0K3WegX+ULR 9m6Dz0ljh9FOgfOtzDrPTAtqkGvz+HQZtKaAZzHW4WFAtjUrhhY1JI4zIvJiEkSg db26IhSqb0+CB15XPZDE+ra5j4QlygOqfUs8fF+SrjkynAQ1ASWsnT+aHplg2nEY VJPaN2LhxWjr6Uo2iVCuzc1vR3Tua/veZACztb2x8QK6sgUcsrH/OY02yFcJ7qyo NhgxnMJSpLB/Mo6BLFjMn2fetePt96RgsO4FDwzDT7h1iGf5vXBBiId9QDk7fvZw Z9wcJkLa1R0CAwEAAaOCAi0wggIpMB0GA1UdDgQWBBSrVN4+XHdiFIwgwiAFIWRX UFRxPzAJBgNVHRMEAjAAMB8GA1UdIwQYMBaAFP02QCKa1fxb8ATJkOZPT4hLRPhO MHgGA1UdIARxMG8wDgYMKwYBBAG0aAUCAgIBMA4GDCsGAQQBtGgFAgIBATA9Bgwr BgEEAbRoBQICBAEwLTArBggrBgEFBQcCARYfaHR0cDovL3d3dy5wa2kudnQuZWR1 L3Z0bXcvY3BzLzAOBgwrBgEEAbRoBQICAwEwgdIGA1UdHwSByjCBxzCBxKCBwaCB voaBu2h0dHA6Ly92dGNhLXAuZXByb3Yuc2V0aS52dC5lZHU6ODA4MC9lamJjYS9w dWJsaWN3ZWIvd2ViZGlzdC9jZXJ0ZGlzdD9jbWQ9Y3JsJmlzc3Vlcj1DTj1WaXJn aW5pYStUZWNoK01pZGRsZXdhcmUrQ0EsTz1WaXJnaW5pYStQb2x5dGVjaG5pYytJ bnN0aXR1dGUrYW5kK1N0YXRlK1VuaXZlcnNpdHksREM9dnQsREM9ZWR1LEM9VVMw CwYDVR0PBAQDAgTwMBMGA1UdJQQMMAoGCCsGAQUFBwMBMGsGA1UdEQRkMGKCFGVk Lm1pZGRsZXdhcmUudnQuZWR1ghBkaXJlY3RvcnkudnQuZWR1ghNpZC5kaXJlY3Rv cnkudnQuZWR1ghZhdXRobi5kaXJlY3RvcnkudnQuZWR1ggtsZGFwLnZ0LmVkdTAN BgkqhkiG9w0BAQUFAAOCAgEABs6vLEbm28l3tpZOy1iWJEZbaXsKwVdMZXQKlQWx QzXNe99ktfzsq1Rf99YhNefcxpwqIb4TKxc9e8hjSH39ySLso3PpjjywSjZzFkVn I/gC+R8Lq6tgFJnEGeRfu6z699ej7YaX21SKqy4+qh+pXTKV9yppch8Wiz440Pbx qTg0/422nFjBoDcfSby9g4GaFcQKsx26MZ3cY+bFZUSVZ9skFlv8hXQ60NnHL23L TzYTje+/7gZAYMRWKQpbBvXGj/cu7cpX56qYNRV9My+xmDxkhv2aJaEyY6kePIY4 4Ziu8PUfSLLK7CZexOyNTbVbbyL31s7ao07v1iXiY8rIJieCOrzEpqMHZ7qaGZVJ 26WL4fgVfGQu8mIWnlcE7R2sa6RtmLBqAHttXozYCuGVxMYYsyoFLg+I8p1wnFAF 4dS6rARiI/dbOrz5z8UokDDaAAfP8FfpyTBzi0mZo85XPZeB2Vy0zQjiZFAuzq8f 9XShx3VnLNz7FIvy2wNQwmLM3LXijL4NzCKo5GAE9KniFr4x9d+iAdzcOyZe5a9i 6KtfZD+9Z7HyV45gzKWR6WmNL9lS44afYNW1dTxQCY7dOo+27nW3eS59rcxHlifc maJA9izvFEMxGDBzu5isUWyj+qp7VFpAm63uHKwy8+wmemm7C8xF04f+QnHpw5MM Bl0= -----END CERTIFICATE-----cryptacular-1.2.5/src/test/resources/certs/entity.crt000066400000000000000000000035471422604312300230040ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIFSzCCBDOgAwIBAgIJAJlvk9MRIyGCMA0GCSqGSIb3DQEBBQUAMIHJMQswCQYD VQQGEwJVUzERMA8GA1UECBMIVmlyZ2luaWExEzARBgNVBAcTCkJsYWNrc2J1cmcx PDA6BgNVBAoTM1ZpcmdpbmlhIFBvbHl0ZWNobmljIEluc3RpdHV0ZSBhbmQgU3Rh dGUgVW5pdmVyc2l0eTETMBEGA1UECxMKTWlkZGxld2FyZTEeMBwGA1UEAxMVQmVh dXJlZ2FyZCBCdW1ibGVmb290MR8wHQYJKoZIhvcNAQkBFhBiZWF1QGV4YW1wbGUu Y29tMB4XDTEyMDIyMzE1MDc0NloXDTM5MDcxMTE1MDc0NlowgckxCzAJBgNVBAYT AlVTMREwDwYDVQQIEwhWaXJnaW5pYTETMBEGA1UEBxMKQmxhY2tzYnVyZzE8MDoG A1UEChMzVmlyZ2luaWEgUG9seXRlY2huaWMgSW5zdGl0dXRlIGFuZCBTdGF0ZSBV bml2ZXJzaXR5MRMwEQYDVQQLEwpNaWRkbGV3YXJlMR4wHAYDVQQDExVCZWF1cmVn YXJkIEJ1bWJsZWZvb3QxHzAdBgkqhkiG9w0BCQEWEGJlYXVAZXhhbXBsZS5jb20w ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDJqxu5wkvp2xIViqPYaqPI LIojitnspRsPHBe7JjPW+rDHx68RNzkht/uCOTvvDPYvKbf7aZyaFQnTQBQMaWqX 1FkwcMRoVHeJpvi8pS5pyuvcu3kpS3U3aT7t6Joi/qhPBZMc9iu8Pe4jIcf8CPQU SCMJoSl1llbM0EBxqxTa9vKTsryt1xkVPM0Of1i5RpC4Y9gipSyKffWH8M0RX2p2 iVu79te0GAwDBmKw2lNLkPodDj8yF78CRnJJw07R8kMVoS0Hi91Sx6NEhbmvc+zi jpF2/RFsOjDBh3Im6V6ejnDwFu8+5P/kuL04nL1I0lG5Urv0js3Jlgn36DuYomXf AgMBAAGjggEyMIIBLjAdBgNVHQ4EFgQUOOaPw5TKHJs6XEi1u13t0oHrVNAwgf4G A1UdIwSB9jCB84AUOOaPw5TKHJs6XEi1u13t0oHrVNChgc+kgcwwgckxCzAJBgNV BAYTAlVTMREwDwYDVQQIEwhWaXJnaW5pYTETMBEGA1UEBxMKQmxhY2tzYnVyZzE8 MDoGA1UEChMzVmlyZ2luaWEgUG9seXRlY2huaWMgSW5zdGl0dXRlIGFuZCBTdGF0 ZSBVbml2ZXJzaXR5MRMwEQYDVQQLEwpNaWRkbGV3YXJlMR4wHAYDVQQDExVCZWF1 cmVnYXJkIEJ1bWJsZWZvb3QxHzAdBgkqhkiG9w0BCQEWEGJlYXVAZXhhbXBsZS5j b22CCQCZb5PTESMhgjAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4IBAQAS WHk3oP64Uat1gBodTpOEPTUvvemEvVvjGGBDZbg+SOA2OYvMrfJTIEYlVcFlGLHU es82gCFdG7BMrqnZlssMNnvGdSS1SIarsfdv82wizBzuqVCHfMQXJ3ar5XfbY5hJ PgnJs/LIRLncB8u0UdmZ2xcUDR5RbFtreXplMboRmzv2MXK7m0PhoctLSDFoMAld RLxXOfD+Geq/ZJC8LLnNaSD483sTltDh4bu1RaQueZ5sb84a2agVnP//LkHwGvxE MfctVFDTeHng7oCA55Jel8nSoPunp4MG5fUwfMb3yp0Dc+C/EJejCpH5dqO5lflw 76/LBZIpF8V3s1jWNbYL -----END CERTIFICATE----- cryptacular-1.2.5/src/test/resources/certs/entity.key000066400000000000000000000032131422604312300227720ustar00rootroot00000000000000-----BEGIN RSA PRIVATE KEY----- MIIEowIBAAKCAQEAyasbucJL6dsSFYqj2GqjyCyKI4rZ7KUbDxwXuyYz1vqwx8ev ETc5Ibf7gjk77wz2Lym3+2mcmhUJ00AUDGlql9RZMHDEaFR3iab4vKUuacrr3Lt5 KUt1N2k+7eiaIv6oTwWTHPYrvD3uIyHH/Aj0FEgjCaEpdZZWzNBAcasU2vbyk7K8 rdcZFTzNDn9YuUaQuGPYIqUsin31h/DNEV9qdolbu/bXtBgMAwZisNpTS5D6HQ4/ Mhe/AkZyScNO0fJDFaEtB4vdUsejRIW5r3Ps4o6Rdv0RbDowwYdyJuleno5w8Bbv PuT/5Li9OJy9SNJRuVK79I7NyZYJ9+g7mKJl3wIDAQABAoIBADwQMUbHHpL9A0rV Ku1m/Xa+BTqGvVck6YU7ibncq+3oZkRqLbMD7okjYc4sO7R7+MqdM0W288RUZcO8 PvxfXTbxMMsjmuuz1JJz33tX+xXZMRxh3bk11yh0uSBkeZvYmspGT8V9cBM1orpl 8kkXZZKw1XalwFJcP2fq0nbITILWKC25vc5QSesuOcpP9rs2f+W/d80eF11EPLXw /cBgqHc9YCk/IAX1vZnXrPep27OzrOmwT7XIQUWQvGA0VjwT3jGE3fF4ZgEbIz3g gZz346tHkIQzjibKiMjxnq1RO+f0leqfaTyomLD0YeSIg14giwS0i3OwvCOhC4bB S0Q7k5ECgYEA9fe3ZDKjfKukYRhEwfoJmD/z4ea7mA+9U4N6Ax/WUa1eRGkLFXDf FCfEIt3/HWW90QN3R2jC7Cc2fZ+QWRzBSuVdvdUZPxEDAvvlWYbIDwblR1rvWeqX wVw2fudKse/1Sr5iAPw+d1vSSUHFkexsxTP0v3iCJQZppe64JeysTAcCgYEA0eTW zJCu9WGh55FSbp/nArk1q3Ezqaf+KFs9VY1oMTigE1DHhHLO8ueBRXwtwRWczVpP uD2xHb9FSKgkyhSXb88rS8E3v/uww8l2bRJDfFe3j87a8T/ChWJSEenH0JA3aisv IQQhqAfh/uj/l6jjEyJqvtojFr5bjUKiwKaPUWkCgYByT/AhVw94D2VT4q2B4Sy4 X3B+2nbw0s/QklgQP6mhSAt5i8Ak9NIYUerrsXSxOumezBeRTnTYv9ipRZEWeTC0 GCka4oDbOJLHvj32/5bWtQO1x+NZTJe+u5ZwIBos3DKJzDVL8+8sFbaDaVfi25gp hl4G5oDFqFdNUMawiXAB3QKBgBTUiRy0HyjrD45TtcKUy/BRQSpKib4ElgybQXME HZsE653/Hk3etvsUTpf+wuuuoWkf1VmLhdBV8yJKzZvgf0bxYHKcMlQzPk+v5rjc XyYv7l+vP7tBgKSMJWjxsorYRSecMYktR8nNPnh11yfN8vsrJzzZmTHgomVaf5xu 6zpBAoGBANyebxHmQwIINzQ8N5zhVo/+jYfLJslNzxg9nb9t2mbO5OAmuZWPrLKt iw17lA6aLc3YORqs0UntQKRRY2Jqv643Uluo9XvHFpITNzpSkjkcGc1TEfuZJD7m k782JevhsWkEaMtiQflAOq3lFH3Go1u+qP/A2klt9jbdexfNu4v2 -----END RSA PRIVATE KEY----- cryptacular-1.2.5/src/test/resources/certs/glider.cc.vt.edu.crt000066400000000000000000000051471422604312300245240ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIHgTCCBWmgAwIBAgIIM9zF+iOD1NIwDQYJKoZIhvcNAQEFBQAwgZoxEzARBgoJ kiaJk/IsZAEZEwNlZHUxEjAQBgoJkiaJk/IsZAEZEwJ2dDELMAkGA1UEBhMCVVMx PDA6BgNVBAoTM1ZpcmdpbmlhIFBvbHl0ZWNobmljIEluc3RpdHV0ZSBhbmQgU3Rh dGUgVW5pdmVyc2l0eTEkMCIGA1UEAxMbVmlyZ2luaWEgVGVjaCBNaWRkbGV3YXJl IENBMB4XDTA5MDcyMDE4MTYzOVoXDTExMDcyMDE4MTYzOVowgfoxGTAXBgNVBAMM EGdsaWRlci5jYy52dC5lZHUxFjAUBgNVBAUTDTEyNDgxMTA2NTc5NjExDTALBgNV BAsMBFNFVEkxGjAYBgNVBAsMEU1pZGRsZXdhcmUtQ2xpZW50MTwwOgYDVQQKDDNW aXJnaW5pYSBQb2x5dGVjaG5pYyBJbnN0aXR1dGUgYW5kIFN0YXRlIFVuaXZlcnNp dHkxEzARBgNVBAcMCkJsYWNrc2J1cmcxETAPBgNVBAgMCFZpcmdpbmlhMRIwEAYK CZImiZPyLGQBGRYCdnQxEzARBgoJkiaJk/IsZAEZFgNlZHUxCzAJBgNVBAYTAlVT MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAs5UbcNcLgGVmyzzrz/rR jnvelOjb6KZVYH+7twTNQ8nrjfKz09xeRGUyYEeeJd4Ma0l+i0kW6i68LsI8Mshm mKQTbMXdGodXrGmqw468+Az9nbp/fsn6N/PYRJedar9i1IqiVzu638RZpvVuo3Vi uZjuj0mHC89NNhUQ0NJaefgsKQ3ksAvvyhHtmk6UZyx4S5bQWQ8rVmGuBRAqUjjT HLde4k2Rid/TVjqT7bAjsIMUKnWx2+tVrx19ePJ2c4XUB9aBIwZ/IMmhVwtpQESn c32G5t8tY7W/vPiHK1dupYkeOhiyLXAClHIipbOBdUnvIzEmuBmv1Ln1t2Z64O0D zQIDAQABo4ICZzCCAmMwHQYDVR0OBBYEFMc2newZJGEJXQtUFUlg6d4+MFpnMAkG A1UdEwQCMAAwHwYDVR0jBBgwFoAU/TZAIprV/FvwBMmQ5k9PiEtE+E4weAYDVR0g BHEwbzAOBgwrBgEEAbRoBQICAgEwDgYMKwYBBAG0aAUCAgEBMD0GDCsGAQQBtGgF AgIEATAtMCsGCCsGAQUFBwIBFh9odHRwOi8vd3d3LnBraS52dC5lZHUvdnRtdy9j cHMvMA4GDCsGAQQBtGgFAgIDATCCAXgGA1UdHwSCAW8wggFrMIIBZ6CBwaCBvoaB u2h0dHA6Ly92dGNhLXAuZXByb3Yuc2V0aS52dC5lZHU6ODA4MC9lamJjYS9wdWJs aWN3ZWIvd2ViZGlzdC9jZXJ0ZGlzdD9jbWQ9Y3JsJmlzc3Vlcj1DTj1WaXJnaW5p YStUZWNoK01pZGRsZXdhcmUrQ0EsTz1WaXJnaW5pYStQb2x5dGVjaG5pYytJbnN0 aXR1dGUrYW5kK1N0YXRlK1VuaXZlcnNpdHksREM9dnQsREM9ZWR1LEM9VVOigaCk gZ0wgZoxJDAiBgNVBAMMG1ZpcmdpbmlhIFRlY2ggTWlkZGxld2FyZSBDQTE8MDoG A1UECgwzVmlyZ2luaWEgUG9seXRlY2huaWMgSW5zdGl0dXRlIGFuZCBTdGF0ZSBV bml2ZXJzaXR5MRIwEAYKCZImiZPyLGQBGRYCdnQxEzARBgoJkiaJk/IsZAEZFgNl ZHUxCzAJBgNVBAYTAlVTMAsGA1UdDwQEAwIE8DATBgNVHSUEDDAKBggrBgEFBQcD AjANBgkqhkiG9w0BAQUFAAOCAgEAoTqj6tu88MnnQ5FzjWnUw4qVtLF9A6Cm/Ku/ g49/LNSvccGoe55OazE1fYjLLGmPkwICey8ijkvj+kzYEHqPKcNCSqPEW2ALOclF obTpUQvxSWieYoLSsJ8oBCjQ4RY03uSVnVvnSx0mhXQZffW0q7qfx8+OhDe4JFKo 4/iizuC8OZuvWvUwV3CkufVUpFNQJZ5ClXqkhad265sw8fTGkqZ8e0ccfzTdlomk UUhsykFagVM071nQ4FtxdCS+Wml5e36ysXqraMVWBv3XGWWI0SiFY1Ol/cewIdZt elHyZYOxBzBLXqfep2GjEVqhqqkBQLiw1WqDJ6FXlz7Lt3V6AQHtT1QT/lcjD7c4 Stj25/Xh89tWVV5ApccdDGT83JHN6dI2rTTkNwFS+PuDY1ogjUyM4O52olGWY7Ws 5xmOf+cDJAzGCdF94OY7c+Z9uyso65r+QpGhCsLnC/dKw6YXrPKz4LC4vJ2g2Cc1 Gb3ZqOCkSt9OHcqLfzaNul7tJx82b7sDdgoTjyVroY5M0lsXEsKh1gFwp3LWiz5N BHI8sSqwAuQP2R5xPij8Lp/0hasWONZNULURisQKFsswyE+6UTbFoEjkFEMrx/pM OcWT490JNHRxcb+fb0UGXZ0Wdm9NKIy1L98EHpkPnNDuiaXs/lhpu56LipUAWdiL 4swBcCA= -----END CERTIFICATE----- cryptacular-1.2.5/src/test/resources/certs/login.live.com.crt000066400000000000000000000040621422604312300243040ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIFxzCCBK+gAwIBAgIQWfjHqoYW0XMXfFBcAW44GzANBgkqhkiG9w0BAQUFADCB ujELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL ExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTswOQYDVQQLEzJUZXJtcyBvZiB1c2Ug YXQgaHR0cHM6Ly93d3cudmVyaXNpZ24uY29tL3JwYSAoYykwNjE0MDIGA1UEAxMr VmVyaVNpZ24gQ2xhc3MgMyBFeHRlbmRlZCBWYWxpZGF0aW9uIFNTTCBDQTAeFw0w OTA2MTYwMDAwMDBaFw0xMDA2MTYyMzU5NTlaMIIBDzETMBEGCysGAQQBgjc8AgED EwJVUzEbMBkGCysGAQQBgjc8AgECEwpXYXNoaW5ndG9uMRswGQYDVQQPExJWMS4w LCBDbGF1c2UgNS4oYikxEjAQBgNVBAUTCTYwMDQxMzQ4NTELMAkGA1UEBhMCVVMx DjAMBgNVBBEUBTk4MDUyMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHFAdS ZWRtb25kMRowGAYDVQQJFBFPbmUgTWljcm9zb2Z0IFdheTEeMBwGA1UEChQVTWlj cm9zb2Z0IENvcnBvcmF0aW9uMREwDwYDVQQLFAhQYXNzcG9ydDEXMBUGA1UEAxQO bG9naW4ubGl2ZS5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAKuYQtRg +njn4QEUtC2TkeJj+LWH2rgmkpEWUE4df1j8/eFzKPnJmdsviZA+KLslQp9EALTM Y6G2wKwDxR9hRz5xmOlvnZB5z4uUfcXYsONETqm7HtWqHzHTyKHJKDv88Vva4eGr 1AgS+M3hzFAaUl/DnpG8sI0Lz2X7dx5xSwSfAgMBAAGjggHzMIIB7zAJBgNVHRME AjAAMB0GA1UdDgQWBBQxrvF8mGfpHxlpoqeEHmdcqsNrdTALBgNVHQ8EBAMCBaAw QgYDVR0fBDswOTA3oDWgM4YxaHR0cDovL0VWU2VjdXJlLWNybC52ZXJpc2lnbi5j b20vRVZTZWN1cmUyMDA2LmNybDBEBgNVHSAEPTA7MDkGC2CGSAGG+EUBBxcGMCow KAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3LnZlcmlzaWduLmNvbS9ycGEwHQYDVR0l BBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMB8GA1UdIwQYMBaAFPyKULqeuSVae1WF T5UAY4/pWGtDMHwGCCsGAQUFBwEBBHAwbjAtBggrBgEFBQcwAYYhaHR0cDovL0VW U2VjdXJlLW9jc3AudmVyaXNpZ24uY29tMD0GCCsGAQUFBzAChjFodHRwOi8vRVZT ZWN1cmUtYWlhLnZlcmlzaWduLmNvbS9FVlNlY3VyZTIwMDYuY2VyMG4GCCsGAQUF BwEMBGIwYKFeoFwwWjBYMFYWCWltYWdlL2dpZjAhMB8wBwYFKw4DAhoEFEtruSiW Bgy70FI4mymsSweLIQUYMCYWJGh0dHA6Ly9sb2dvLnZlcmlzaWduLmNvbS92c2xv Z28xLmdpZjANBgkqhkiG9w0BAQUFAAOCAQEAdjzxBfnaVmlbOWci+BnXY9hZZqSK sqk0CrsdBQXot+PcPpzfi4cdUc8/8Pr6SvLAqi/koHc6ez0SxK1QycfuwAUVCKsd /np79v2K94UHuKb+NTzHUStBg3KoSe7/mK3gP1CSSpgr9u+wHjQhjdIYrozHJD2C T/cjX4A1EZy5ChV719L7UiganmT6jOY2+ogP3ppd1WgZHnCGHciUaiR6kjw9p6UD jM19Lg3DHnw9zxjFHTj+MFc9qLBb3m7QEdEOO1hwQdWYS08bjEXvuuISO0tEr28X 5ir3zGxe66Ge0Koi2AM1y9gq8+bOVqDudU2poyIXfFXcQ13HRNtgvnH3fQ== -----END CERTIFICATE----- cryptacular-1.2.5/src/test/resources/certs/multi-value-rdn-1.crt000066400000000000000000000020321422604312300246370ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIC2zCCAkSgAwIBAgIDAVJ9MA0GCSqGSIb3DQEBBQUAMFcxEzARBgoJkiaJk/Is ZAEZFgNvcmcxGDAWBgoJkiaJk/IsZAEZFghsZGFwdGl2ZTESMBAGA1UEAxMJYS5m b28uY29tMRIwEAYDVQQDEwliLmZvby5jb20wHhcNMTQwODI5MTk1MTE5WhcNMTQw OTI4MTk1MTE5WjBXMRMwEQYKCZImiZPyLGQBGRYDb3JnMRgwFgYKCZImiZPyLGQB GRYIbGRhcHRpdmUxEjAQBgNVBAMTCWEuZm9vLmNvbTESMBAGA1UEAxMJYi5mb28u Y29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrFV0ARzYvBJLXMLo8yex7 aNATrAANh4S3utE/ce+xj2qTi+hl9xm0EU6Zal+iYGpsKqnpTPfNE8HVMbzOrrPB 6fRMGS1AyRV3WOy+2mgdzi1P068PqpTkm+MjXF6El8OBnuGaIwLzvFMno0rV7lse UOLDYcEIl3BdVsIlH27KpQIDAQABo4G0MIGxMB0GA1UdDgQWBBSHRs4AN3PGdL/i OkPq/Cjjc6f8EDCBgQYDVR0jBHoweIAUh0bOADdzxnS/4jpD6vwo43On/BChW6RZ MFcxEzARBgoJkiaJk/IsZAEZFgNvcmcxGDAWBgoJkiaJk/IsZAEZFghsZGFwdGl2 ZTESMBAGA1UEAxMJYS5mb28uY29tMRIwEAYDVQQDEwliLmZvby5jb22CAwFSfTAM BgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4GBAC++ms/hrIOiY4Gdyie8qiIW FAU/IZLkbFSPwFpVQrYLdN7m+xCIcq2+viaZdXG6QYOC8dYr2URoEoVm+DPfx2Hj TokXEIsNS7ODx8r/sBmJ2UHvRdPROtqwY4tCgYlf7LWD/s27eRVYCTZbcwMF1hBf aNe1VTBZ5MLkzyewZ6tW -----END CERTIFICATE----- cryptacular-1.2.5/src/test/resources/certs/multi-value-rdn-2.crt000066400000000000000000000020221422604312300246370ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIC1DCCAj2gAwIBAgIDAVJ9MA0GCSqGSIb3DQEBBQUAMFUxJDAQBgNVBAMTCWEu Zm9vLmNvbTAQBgNVBAMTCWIuZm9vLmNvbTEYMBYGCgmSJomT8ixkARkWCGxkYXB0 aXZlMRMwEQYKCZImiZPyLGQBGRYDb3JnMB4XDTE0MDgyOTE5MjY1OVoXDTE0MDky ODE5MjY1OVowVTEkMBAGA1UEAxMJYS5mb28uY29tMBAGA1UEAxMJYi5mb28uY29t MRgwFgYKCZImiZPyLGQBGRYIbGRhcHRpdmUxEzARBgoJkiaJk/IsZAEZFgNvcmcw gZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAOC2KBN8MDiKHWEuv1pnIEcWYjHb D+NgAGVnZh7i8jEDRIVpWUzFj7FxNROEsAitZAanzpwo6jYeGmT60Vl4DpliuoVu Vt1Reem96Dp9/J7BL0QBv0fJErv/YRhNor4wSOuWI96TWHvCDEL4oDNuxEK46Nsn dAw10DFBRMWt1VcFAgMBAAGjgbEwga4wHQYDVR0OBBYEFB7EPqv9y/GqxBrJAMS4 pEh2ktyTMH8GA1UdIwR4MHaAFB7EPqv9y/GqxBrJAMS4pEh2ktyToVmkVzBVMSQw EAYDVQQDEwlhLmZvby5jb20wEAYDVQQDEwliLmZvby5jb20xGDAWBgoJkiaJk/Is ZAEZFghsZGFwdGl2ZTETMBEGCgmSJomT8ixkARkWA29yZ4IDAVJ9MAwGA1UdEwQF MAMBAf8wDQYJKoZIhvcNAQEFBQADgYEALU4SluqREjvyztZDZRsVnKn0Wy5kQqh3 wVN/U2Sv82+N6ulzqOttmEY/dq8UGH5QbIioGUTgWxycidYwzWCIT/+Gg+pwBcmz oTYxJY0aUKfvfy4p25dcaG360DMycUpmZHM+HpgEGOrMsLCewKshuR+D03pE9eH5 AK1FbieXQtM= -----END CERTIFICATE----- cryptacular-1.2.5/src/test/resources/certs/needs-escaping-1.crt000066400000000000000000000024161422604312300245050ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIDjTCCAvagAwIBAgIJAJ9OE8QRbtsRMA0GCSqGSIb3DQEBBQUAMIGMMRMwEQYK CZImiZPyLGQBGRYDZWR1MRIwEAYKCZImiZPyLGQBGRYCdnQxCzAJBgNVBAYTAlVT MREwDwYDVQQIEwhWaXJnaW5pYTETMBEGA1UEBxMKQmxhY2tzYnVyZzEPMA0GA1UE ChQGVlBJJlNVMRswGQYDVQQDExJEQz1leGFtcGxlLCBEQz1jb20wHhcNMTQxMDI5 MTE0MzUzWhcNNDIwMzE2MTE0MzUzWjCBjDETMBEGCgmSJomT8ixkARkWA2VkdTES MBAGCgmSJomT8ixkARkWAnZ0MQswCQYDVQQGEwJVUzERMA8GA1UECBMIVmlyZ2lu aWExEzARBgNVBAcTCkJsYWNrc2J1cmcxDzANBgNVBAoUBlZQSSZTVTEbMBkGA1UE AxMSREM9ZXhhbXBsZSwgREM9Y29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB gQDkYYrsisNd/+lNvWR3ridkbPg0VJKc9juQAnSrdh3rV99wBtg0SQeao5MUPwsm LG3/aQmzNhaFNPeWHcQZDmqZO1QLTB7rFX2xZn3t4uD2+yn764lnL10qliZmGCbs 6wB4LLrnR50hWYx3MgisdeHe4uOc18FVGvGs8+2k0Im/yQIDAQABo4H0MIHxMB0G A1UdDgQWBBQVpddz37M6vpI2uk5lLDByhWTNxTCBwQYDVR0jBIG5MIG2gBQVpddz 37M6vpI2uk5lLDByhWTNxaGBkqSBjzCBjDETMBEGCgmSJomT8ixkARkWA2VkdTES MBAGCgmSJomT8ixkARkWAnZ0MQswCQYDVQQGEwJVUzERMA8GA1UECBMIVmlyZ2lu aWExEzARBgNVBAcTCkJsYWNrc2J1cmcxDzANBgNVBAoUBlZQSSZTVTEbMBkGA1UE AxMSREM9ZXhhbXBsZSwgREM9Y29tggkAn04TxBFu2xEwDAYDVR0TBAUwAwEB/zAN BgkqhkiG9w0BAQUFAAOBgQDDyLykXoVgJroG5iSbebWrZALT0XzEN/gfxYxAYEh7 YUrjM3GUHpF+dKroh/lreWn+fbO1oALuqSODnDmYPIYGeemS22P798ab8ar7ltNt pVGjaQk5w+GPvXA1LTAFWlb/2kHQAFEE0+oKz6PEZxtJy0StDQvfc4bQ3dW7ddOC Kg== -----END CERTIFICATE----- cryptacular-1.2.5/src/test/resources/certs/needs-escaping-2.crt000066400000000000000000000023511422604312300245040ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIDcjCCAtugAwIBAgIJALpZTTXEfhcxMA0GCSqGSIb3DQEBBQUAMIGDMRMwEQYK CZImiZPyLGQBGRYDZWR1MRIwEAYKCZImiZPyLGQBGRYCdnQxCzAJBgNVBAYTAlVT MREwDwYDVQQIEwhWaXJnaW5pYTETMBEGA1UEBxMKQmxhY2tzYnVyZzEPMA0GA1UE ChQGVlBJJlNVMRIwEAYDVQQDFAkjREVBREJFRUYwHhcNMTQxMDI5MTMxNDIxWhcN NDIwMzE2MTMxNDIxWjCBgzETMBEGCgmSJomT8ixkARkWA2VkdTESMBAGCgmSJomT 8ixkARkWAnZ0MQswCQYDVQQGEwJVUzERMA8GA1UECBMIVmlyZ2luaWExEzARBgNV BAcTCkJsYWNrc2J1cmcxDzANBgNVBAoUBlZQSSZTVTESMBAGA1UEAxQJI0RFQURC RUVGMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkYYrsisNd/+lNvWR3ridk bPg0VJKc9juQAnSrdh3rV99wBtg0SQeao5MUPwsmLG3/aQmzNhaFNPeWHcQZDmqZ O1QLTB7rFX2xZn3t4uD2+yn764lnL10qliZmGCbs6wB4LLrnR50hWYx3MgisdeHe 4uOc18FVGvGs8+2k0Im/yQIDAQABo4HrMIHoMB0GA1UdDgQWBBQVpddz37M6vpI2 uk5lLDByhWTNxTCBuAYDVR0jBIGwMIGtgBQVpddz37M6vpI2uk5lLDByhWTNxaGB iaSBhjCBgzETMBEGCgmSJomT8ixkARkWA2VkdTESMBAGCgmSJomT8ixkARkWAnZ0 MQswCQYDVQQGEwJVUzERMA8GA1UECBMIVmlyZ2luaWExEzARBgNVBAcTCkJsYWNr c2J1cmcxDzANBgNVBAoUBlZQSSZTVTESMBAGA1UEAxQJI0RFQURCRUVGggkAullN NcR+FzEwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOBgQAOxmoFF9gRDiuA l+z0/stcxChGAkdKYGXL62U/L6POvwxLUnpvWgBX21KcIub2wICCMo/JA81s2QFk LwaxBpXp6awCN0H+H5HH60hr9Q3optPxFxzeAb8L/TlP4ClcsnKrpY9Ge69Hp8GD yqBVXG9iHAz3RpE10pJA4f/NFD7ZLQ== -----END CERTIFICATE----- cryptacular-1.2.5/src/test/resources/certs/needs-escaping-3.crt000066400000000000000000000023351422604312300245070ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIDaTCCAtKgAwIBAgIJALRAX7xeRlE+MA0GCSqGSIb3DQEBBQUAMIGAMRMwEQYK CZImiZPyLGQBGRYDZWR1MRIwEAYKCZImiZPyLGQBGRYCdnQxCzAJBgNVBAYTAlVT MREwDwYDVQQIEwhWaXJnaW5pYTETMBEGA1UEBxMKQmxhY2tzYnVyZzEPMA0GA1UE ChQGVlBJJlNVMQ8wDQYDVQQDEwYgc3BhY2UwHhcNMTQxMDI5MTMxNjM4WhcNNDIw MzE2MTMxNjM4WjCBgDETMBEGCgmSJomT8ixkARkWA2VkdTESMBAGCgmSJomT8ixk ARkWAnZ0MQswCQYDVQQGEwJVUzERMA8GA1UECBMIVmlyZ2luaWExEzARBgNVBAcT CkJsYWNrc2J1cmcxDzANBgNVBAoUBlZQSSZTVTEPMA0GA1UEAxMGIHNwYWNlMIGf MA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkYYrsisNd/+lNvWR3ridkbPg0VJKc 9juQAnSrdh3rV99wBtg0SQeao5MUPwsmLG3/aQmzNhaFNPeWHcQZDmqZO1QLTB7r FX2xZn3t4uD2+yn764lnL10qliZmGCbs6wB4LLrnR50hWYx3MgisdeHe4uOc18FV GvGs8+2k0Im/yQIDAQABo4HoMIHlMB0GA1UdDgQWBBQVpddz37M6vpI2uk5lLDBy hWTNxTCBtQYDVR0jBIGtMIGqgBQVpddz37M6vpI2uk5lLDByhWTNxaGBhqSBgzCB gDETMBEGCgmSJomT8ixkARkWA2VkdTESMBAGCgmSJomT8ixkARkWAnZ0MQswCQYD VQQGEwJVUzERMA8GA1UECBMIVmlyZ2luaWExEzARBgNVBAcTCkJsYWNrc2J1cmcx DzANBgNVBAoUBlZQSSZTVTEPMA0GA1UEAxMGIHNwYWNlggkAtEBfvF5GUT4wDAYD VR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOBgQB14f+JlFDdZPIxYpNXGCDNaemw zPDUs7YDzXAfVgkbw/mt36155d7jXnmzkPnDZbCeIc/CGmgOURmY5WOS5m1eVywu cliBoYA5xQBfNUVMa+68wvLzY7jQbGyKm9CFIwNjNMhDF5uenpyv/DxwvMd7Wneq XluBRl3MN4DV9aULOg== -----END CERTIFICATE----- cryptacular-1.2.5/src/test/resources/certs/needs-escaping-4.crt000066400000000000000000000023451422604312300245110ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIDbzCCAtigAwIBAgIJALu4vu81OOfsMA0GCSqGSIb3DQEBBQUAMIGCMRMwEQYK CZImiZPyLGQBGRYDZWR1MRIwEAYKCZImiZPyLGQBGRYCdnQxCzAJBgNVBAYTAlVT MREwDwYDVQQIEwhWaXJnaW5pYTETMBEGA1UEBxMKQmxhY2tzYnVyZzEPMA0GA1UE ChQGVlBJJlNVMREwDwYDVQQDEwhzcGFjZTIgIDAeFw0xNDEwMjkxMzE3MzJaFw00 MjAzMTYxMzE3MzJaMIGCMRMwEQYKCZImiZPyLGQBGRYDZWR1MRIwEAYKCZImiZPy LGQBGRYCdnQxCzAJBgNVBAYTAlVTMREwDwYDVQQIEwhWaXJnaW5pYTETMBEGA1UE BxMKQmxhY2tzYnVyZzEPMA0GA1UEChQGVlBJJlNVMREwDwYDVQQDEwhzcGFjZTIg IDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA5GGK7IrDXf/pTb1kd64nZGz4 NFSSnPY7kAJ0q3Yd61ffcAbYNEkHmqOTFD8LJixt/2kJszYWhTT3lh3EGQ5qmTtU C0we6xV9sWZ97eLg9vsp++uJZy9dKpYmZhgm7OsAeCy650edIVmMdzIIrHXh3uLj nNfBVRrxrPPtpNCJv8kCAwEAAaOB6jCB5zAdBgNVHQ4EFgQUFaXXc9+zOr6SNrpO ZSwwcoVkzcUwgbcGA1UdIwSBrzCBrIAUFaXXc9+zOr6SNrpOZSwwcoVkzcWhgYik gYUwgYIxEzARBgoJkiaJk/IsZAEZFgNlZHUxEjAQBgoJkiaJk/IsZAEZFgJ2dDEL MAkGA1UEBhMCVVMxETAPBgNVBAgTCFZpcmdpbmlhMRMwEQYDVQQHEwpCbGFja3Ni dXJnMQ8wDQYDVQQKFAZWUEkmU1UxETAPBgNVBAMTCHNwYWNlMiAgggkAu7i+7zU4 5+wwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOBgQC5fERd6NiAzDWY/Rlc YETf6pHrWrGsnB29Mj/PNuSj04pEJ00/LuVEzV56q7vFjjrPh7PkaOH7dAedtDRZ g4YEJY4hS8WZa5NavBtDjidQUQknoL6vQDi4rHEAXoJF/Ol2Zb+XCJCPyJjoR+Ae 28EAHhfJKxysA9t16aI7UN/MqA== -----END CERTIFICATE----- cryptacular-1.2.5/src/test/resources/certs/scantor-dn-description.crt000066400000000000000000000043201422604312300260470ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIGOTCCBSGgAwIBAgIDC9q0MA0GCSqGSIb3DQEBBQUAMIGMMQswCQYDVQQGEwJJ TDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0 YWwgQ2VydGlmaWNhdGUgU2lnbmluZzE4MDYGA1UEAxMvU3RhcnRDb20gQ2xhc3Mg MSBQcmltYXJ5IEludGVybWVkaWF0ZSBDbGllbnQgQ0EwHhcNMTQxMTEwMDI1MzE2 WhcNMTUxMTExMTM0ODI4WjBXMRkwFwYDVQQNExA2TXRwSlMxZGNDN3QyNTR2MRkw FwYDVQQDDBBjYW50b3IuMkBvc3UuZWR1MR8wHQYJKoZIhvcNAQkBFhBjYW50b3Iu MkBvc3UuZWR1MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyIP4AzEq 67t3w/K3qKRp+8DYzPUFCA2tkuxBHEZRGeOK2xx2mZm9anw0lO1ihNm2Td6xaOnP RKeIdl2eMX7AEzVazMaDYAB8n+qxQLC5+2R98wrqsp685YjE0siczBDTKkReXtea yhxP6vuJTtnAfSf7caa+U5RqWxfPf9bGAb378P9eNQ4xXpaR3VjVBL+Bnh5pSYzT bxj2fpGzNUAh5pi/QD6pxZ+cXyc3SB2hmX1QoFPDlEjuXBrOJKW2rBJ/58Mah+gS V0cCt9YVgeONNytpr4IbjcdZj356VJav07gfrhwdlIDOhFsrq/1aHvwttUeaUQ+E AWuRwR5XfOrU6QIDAQABo4IC1jCCAtIwCQYDVR0TBAIwADALBgNVHQ8EBAMCBLAw HQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMEMB0GA1UdDgQWBBTE8bu/7pUs M37CLGlLPPfH/tTtcDAfBgNVHSMEGDAWgBRTcu2SnODaywFcfH6WNU7y1LhRgjAb BgNVHREEFDASgRBjYW50b3IuMkBvc3UuZWR1MIIBTAYDVR0gBIIBQzCCAT8wggE7 BgsrBgEEAYG1NwECAzCCASowLgYIKwYBBQUHAgEWImh0dHA6Ly93d3cuc3RhcnRz c2wuY29tL3BvbGljeS5wZGYwgfcGCCsGAQUFBwICMIHqMCcWIFN0YXJ0Q29tIENl cnRpZmljYXRpb24gQXV0aG9yaXR5MAMCAQEagb5UaGlzIGNlcnRpZmljYXRlIHdh cyBpc3N1ZWQgYWNjb3JkaW5nIHRvIHRoZSBDbGFzcyAxIFZhbGlkYXRpb24gcmVx dWlyZW1lbnRzIG9mIHRoZSBTdGFydENvbSBDQSBwb2xpY3ksIHJlbGlhbmNlIG9u bHkgZm9yIHRoZSBpbnRlbmRlZCBwdXJwb3NlIGluIGNvbXBsaWFuY2Ugb2YgdGhl IHJlbHlpbmcgcGFydHkgb2JsaWdhdGlvbnMuMDYGA1UdHwQvMC0wK6ApoCeGJWh0 dHA6Ly9jcmwuc3RhcnRzc2wuY29tL2NydHUxLWNybC5jcmwwgY4GCCsGAQUFBwEB BIGBMH8wOQYIKwYBBQUHMAGGLWh0dHA6Ly9vY3NwLnN0YXJ0c3NsLmNvbS9zdWIv Y2xhc3MxL2NsaWVudC9jYTBCBggrBgEFBQcwAoY2aHR0cDovL2FpYS5zdGFydHNz bC5jb20vY2VydHMvc3ViLmNsYXNzMS5jbGllbnQuY2EuY3J0MCMGA1UdEgQcMBqG GGh0dHA6Ly93d3cuc3RhcnRzc2wuY29tLzANBgkqhkiG9w0BAQUFAAOCAQEAnk+/ 4X15nDhpqiLPkfH0jg4QMkWsniANJtfPoLcbjlhpTxRgIpEHlqY2hdw/gwcMDL0y CjCs2/yhZINITU6YmOnOkalXqKkgy7RxGRYIpjb5XYJbQv+RR+qpzl5S38HQzUDu +Z3r83lYrZFM5scqvl2bzK+2jUchQoM3iClr4ZmmgdJyBM5SEVgHjeQOQI5p7NhO B4eLZ5USBFLK5gVQEkqJjAxZTz72uCHsjPaoiyraZnuZyrct75g/adSfyoJvXuHw rd/RrbJJcx96Eqf1v26StKcU0eXTc7hIkSshNef3LSKqPbBOojp0JaPJ0AIyvQcs rZoJ0wA8Ifva+t2QvA== -----END CERTIFICATE----- cryptacular-1.2.5/src/test/resources/certs/serac-dev-test.crt000066400000000000000000000162371422604312300243160ustar00rootroot00000000000000Bag Attributes localKeyID: 01 00 00 00 subject=/UID=1145718/CN=Marvin S Addison/O=Virginia Polytechnic Institute and State University/DC=edu/DC=vt/C=US issuer=/DC=edu/DC=vt/C=US/O=Virginia Polytechnic Institute and State University/CN=DEV Virginia Tech Class 1 Server CA/serialNumber=12 -----BEGIN CERTIFICATE----- MIIFfzCCA2egAwIBAgIIL1b8rywTgSMwDQYJKoZIhvcNAQEFBQAwga8xEzARBgoJ kiaJk/IsZAEZFgNlZHUxEjAQBgoJkiaJk/IsZAEZFgJ2dDELMAkGA1UEBhMCVVMx PDA6BgNVBAoTM1ZpcmdpbmlhIFBvbHl0ZWNobmljIEluc3RpdHV0ZSBhbmQgU3Rh dGUgVW5pdmVyc2l0eTEsMCoGA1UEAxMjREVWIFZpcmdpbmlhIFRlY2ggQ2xhc3Mg MSBTZXJ2ZXIgQ0ExCzAJBgNVBAUTAjEyMB4XDTA5MDEyNzE0MzkwMloXDTExMDEy NzE0MzkwMlowgagxFzAVBgoJkiaJk/IsZAEBDAcxMTQ1NzE4MRkwFwYDVQQDDBBN YXJ2aW4gUyBBZGRpc29uMTwwOgYDVQQKDDNWaXJnaW5pYSBQb2x5dGVjaG5pYyBJ bnN0aXR1dGUgYW5kIFN0YXRlIFVuaXZlcnNpdHkxEzARBgoJkiaJk/IsZAEZFgNl ZHUxEjAQBgoJkiaJk/IsZAEZFgJ2dDELMAkGA1UEBhMCVVMwgZ8wDQYJKoZIhvcN AQEBBQADgY0AMIGJAoGBAJqNBYMDpUcDTAI9Srrj473GzqUPB2GFyJMNUy8ebWPE iwsMJlLZRHpC2igDRvDuS/70Jm5YpuVdqr5rnotCgVpczGCP8mE0QBziktLTuLdf Vzbu06/F77GHGUkSJ5TNL0iUynk+zxVvyZA5nAZVpaPqCkKG1xs+Y1Mm34F4EA5t AgMBAAGjggEmMIIBIjAdBgNVHQ4EFgQUJUgvKOxdGbsdJa6Uk7F7tTWWJGYwCQYD VR0TBAIwADAfBgNVHSMEGDAWgBQ44G+uSO1eI/Yimx7nnBkWR7h+kjCBgwYDVR0g BHwwejAOBgwrBgEEAbRoBQICAgEwDgYMKwYBBAG0aAUCAgEBMEgGDCsGAQQBtGgF AgIEATA4MDYGCCsGAQUFBwIBFipodHRwOi8vd3d3LnBraS52dC5lZHUvdnR1Y2Ev Y3BzL2luZGV4Lmh0bWwwDgYMKwYBBAG0aAUCAgMBMAsGA1UdDwQEAwIGwDApBgNV HSUEIjAgBggrBgEFBQcDAgYIKwYBBQUHAwQGCisGAQQBgjcUAgIwFwYDVR0RBBAw DoEMZXByb3ZAdnQuZWR1MA0GCSqGSIb3DQEBBQUAA4ICAQBzUOeoIl4dN89hx5c1 rCQ0zxRn1y3MGWvTLuJnAItnruTbqZWXlMjlGMlW7PY4ZacLcsDC8O2dUYojXiDr vjxykMNf+upCRUpKdlwQNeE7NaB99GnZCK2tavVVXF8B1hfoucvLghN9jPtI0mtI NoSVpUAaU81fTgkkEDP4P8TeBFokj7ygahRGBq6+6ogXQovZqn1jqH+GG/rUUO21 flHw0fQ4MsRWOPXSkiubEn/JbRXsN4dznaoxpAsudl8r3qCf+A3ka6Q1P1ITQxLS aL6dP5GdipBB1Wq+cx/wZ4W2ZdAj9sFY1M8WXDo92i1KsobaRXtbuKgJMTSS8I54 sRdpNzTxVnfrm5ZKm3IoLIqGbaV7HBs26qj+LMbb9XaDVnubRp+cLD4moTcEbEFI jOmykuTsfvZryfZF3Db82GZ0lrLdVr+fnc16PY/943cX7ZhjBUPTjlklwzQs7/VK 6tAlzkfk6Qi0yJlZXGLp2+KZP0eTICB6h2/8udoqI6t6fVxm92JqWNfvFURt2m9t ayrNXSbTXq/KY2DcrMoYk3slqMpGnKlD+iIJQsbjOMmK8a1BMgEAZEDhzCabtQt6 TtJq/v9XFvRPzDiHHmAMkbrJLA0DzpIKICdtovVsskPGov5zv7MalSFJ3+1Cwi0w phTkNox9q4S8XAaRUPS7swqefQ== -----END CERTIFICATE----- Bag Attributes: subject=/C=US/ST=Virginia /L=Blacksburg/O=DEV Virginia Tech Root CA issuer=/C=US/ST=Virginia /L=Blacksburg/O=DEV Virginia Tech Root CA -----BEGIN CERTIFICATE----- MIIGQzCCBCugAwIBAgIBADANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJVUzES MBAGA1UECBMJVmlyZ2luaWEgMRMwEQYDVQQHEwpCbGFja3NidXJnMSIwIAYDVQQK ExlERVYgVmlyZ2luaWEgVGVjaCBSb290IENBMB4XDTAzMDgyNzE5Mzk0M1oXDTMz MDgxOTE5Mzk0M1owWjELMAkGA1UEBhMCVVMxEjAQBgNVBAgTCVZpcmdpbmlhIDET MBEGA1UEBxMKQmxhY2tzYnVyZzEiMCAGA1UEChMZREVWIFZpcmdpbmlhIFRlY2gg Um9vdCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANnl4lsx9H3P ktcm1B6b4nRaRZ1MiBjr3BVLH/GQbhC7rS9hq5B03j9LbN0/ld1aWa+ot6gibBvF cCGweAHkU878CVTEUr/CrvesY0FOggaj7ucCWPOxCxv6Dob+FT1RLO1Bd7YUVLN7 WlMHwi/KX4ADytbNyu7DBDG9PQE4ZmI/9JKBIjpiY6EfjDDIMyRfqK9Gz1mpsVlo kYJBZDa37bNsZ+tIjdm61n2ramdjQxnH9DN1BPvQsm1IoRFD2JeVmYq6jJcmV+Wy Gy1U4WNUe2MxX/y5IEhUmerOnJs1tz7e9qoPJ5MqwSC/ujZ+J/3NmrZK1kc/o3AF 5dZSejFZBIL2hdXVzFeblBYgwMYiLEqdykYo5Y/fFPe6k9VVDNAMraJsFpR7/2ks fENyS6bTZgX3bHeq2WJiQ92BDC5F32QZKFsCArdP8Cdy2J1O2BnFjVB9s3vlLy6X sPjtDtdyCsbuxYHRZT2wWDKKDcIrcSs+3fai5j0MpKPGdwjoK/uxBqjcwAai5XAW NG9ZY2K1+l0oLcw3exi3RUXLLWCu4KjIwQXh0dA1O0hSp+iHaCgW4S7s7EA37zG5 /dOpNVFyZlJB4zOYxmrKt1XtOubOZ+GubeuQiS2xjvZKgyhulV6hdORO7VAgTgKA NMbKnbGCXMW7nU4InkXnPtD0X7j6/HnvAgMBAAGjggESMIIBDjAPBgNVHRMBAf8E BTADAQH/MB0GA1UdDgQWBBTwC6Mn1xo3SrY1FN+8p796K1cdCzCBggYDVR0jBHsw eYAU8AujJ9caN0q2NRTfvKe/eitXHQuhXqRcMFoxCzAJBgNVBAYTAlVTMRIwEAYD VQQIEwlWaXJnaW5pYSAxEzARBgNVBAcTCkJsYWNrc2J1cmcxIjAgBgNVBAoTGURF ViBWaXJnaW5pYSBUZWNoIFJvb3QgQ0GCAQAwCwYDVR0PBAQDAgEGMEoGA1UdIARD MEEwPwYMKwYBBAG0aAUCAQEBMC8wLQYIKwYBBQUHAgEWIWh0dHA6Ly93d3cucGtp LnZ0LmVkdS9yb290Y2EvY3BzLzANBgkqhkiG9w0BAQUFAAOCAgEAE1YKsusecsvV igS4vIlxuSVjxNVA2nyr25G6+jW5ZGwn4osLGh3wRGi6omPWRufctmXcj1K47Scl /wdUmYgprKNlQ3ZwnC03aDFrMBePdT3Iyc6tdS4s4WTH+YxUvHDOht5hGd8yjOEP 1Kh3Iv+WKA3Y4Lt3k5dvYVyz/5Z1vnGFZ/0WU6ICz8rPewKHB0oGiGR2vuJ6g/pH QgSeR0bcUEubo3rBEb0E5GOGrjG4JIzZfH08tq82dGRfxODRgAZV8mMLfbkUluBV ilafwXHLWSgD0CooqmnIDnQJrmsZQssG5wjI2cclwdRZJvVB+Gxy9W7LvLQcRPvf 8ojL6BCC7qkd3zXCdRcpBITTKf1xz1JcUmit2NJHFhmgv1JWwsmGRjGRCjtgLhkG 4fEKP8eY8WeiOGsRzmcZzxe8jWjeUO6ghF3T2R1vdcMCUdn21DO/l62lhR2qC+Ji EDQZvciLZbltTxc0kbHNLXiET1wMHrq50WVM6F6pG7OzEwjXiQPXTPZqRU54ZCuA x3IIJ7pJTzmYGQSISn8QEFDJMmeX8/lWdUJuCAUf1ERO958VD6bSvgK1TasPHtzb xdPfyWvXAvetCNPJLBQAWs4V8SKx71brRn5/ZXBCMd8tqdtwhUyDQqlPpe7kBeGA STDp+xbGH4LUxg/5gUXPiYrqaVCM7GA= -----END CERTIFICATE----- Bag Attributes: subject=/DC=edu/DC=vt/C=US/O=Virginia Polytechnic Institute and State University/CN=DEV Virginia Tech Class 1 Server CA/serialNumber=12 issuer=/C=US/ST=Virginia /L=Blacksburg/O=DEV Virginia Tech Root CA -----BEGIN CERTIFICATE----- MIIG1DCCBLygAwIBAgIBDDANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJVUzES MBAGA1UECBMJVmlyZ2luaWEgMRMwEQYDVQQHEwpCbGFja3NidXJnMSIwIAYDVQQK ExlERVYgVmlyZ2luaWEgVGVjaCBSb290IENBMB4XDTA1MDEwMzE0Mjg0MVoXDTE1 MDEwMTE0Mjg0MVowga8xEzARBgoJkiaJk/IsZAEZFgNlZHUxEjAQBgoJkiaJk/Is ZAEZFgJ2dDELMAkGA1UEBhMCVVMxPDA6BgNVBAoTM1ZpcmdpbmlhIFBvbHl0ZWNo bmljIEluc3RpdHV0ZSBhbmQgU3RhdGUgVW5pdmVyc2l0eTEsMCoGA1UEAxMjREVW IFZpcmdpbmlhIFRlY2ggQ2xhc3MgMSBTZXJ2ZXIgQ0ExCzAJBgNVBAUTAjEyMIIC IDANBgkqhkiG9w0BAQEFAAOCAg0AMIICCAKCAgEA6Gbe+Q+Lx5uphTbuXVAriztF OOLU8/MUtidl1O7aifyiliUq7YqYbZ4Ma1twNEYxRSkrO9L+ljihOBPDOlEwgnAl yXxXIeRobyWxKuDwzC2DggLx1ufmj45iM0TrJ/+XAyo0jgnIxE4cvbFxMgA4AQYP YcxNmPtMdGSdLS5PgEp2DekA5a3K6dD4G6RxSW1YHfZMAzz7k3Mm30usHOw0qKgJ Hvdm50wBXZ+Epd+UUOvHvH8IuDyezvW11Ci/skRrvRYV2aYABy5WFZxVPNMUC5lI gHYuE0Q+gaVp9NJrHi0M/Ks6EFPeMlgKFoevxqluQHzHdOcfgOHD0Hzi5Urqspju mg+KJ5RzzsohLYsjXO0c0nMyzI3aaviZJ9vux7UhsJC8+sxX1hc/C5QubSi1NCEA t1GbH4tsWzhZwja++fTEz8cdOQ2M04PdZj2AltqmbKzse0Mn54XKg5h58hyxxx5z VEURnjV6lYVSxmWlVPviXkYO4i1+/UGmtAgNXdDCajS8PQGHCm4yukbhGFQxiwKQ xi+UaylVK3djr2+emEjGfHIRC5gLAyI687YExUIRbTM8UUfwirieGlEbEqYK9TQw 8jDKp9S/P+hU/AA42QouM3jso1VV63J27cXZSUMsIcwUov6MIUccj/Vaf1PN9K/h Dz3ebY66xX9eT/VrXqcCAQOjggFPMIIBSzAPBgNVHRMBAf8EBTADAQH/MAsGA1Ud DwQEAwIBBjAdBgNVHQ4EFgQUOOBvrkjtXiP2Ipse55wZFke4fpIwgYIGA1UdIwR7 MHmAFPALoyfXGjdKtjUU37ynv3orVx0LoV6kXDBaMQswCQYDVQQGEwJVUzESMBAG A1UECBMJVmlyZ2luaWEgMRMwEQYDVQQHEwpCbGFja3NidXJnMSIwIAYDVQQKExlE RVYgVmlyZ2luaWEgVGVjaCBSb290IENBggEAMDsGA1UdHwQ0MDIwMKAuoCyGKmh0 dHA6Ly93d3cucGtpLnZ0LmVkdS9yb290Y2EvY3JsL2NhY3JsLmNybDBKBgNVHSAE QzBBMD8GDCsGAQQBtGgFAgEBATAvMC0GCCsGAQUFBwIBFiFodHRwOi8vd3d3LnBr aS52dC5lZHUvcm9vdGNhL2Nwcy8wDQYJKoZIhvcNAQEFBQADggIBAIylwmlnOevb PGL6TuRsHtXfN9Ext+HarJ+MZrH0zoDCpC3yOytNiuazDJA4fwD8Q3Km5OrYF2SL KAy6AaeTffEB9w4/MoNmr4qNMc0yx4IxcQuGuNq47L/jDCp332WNFkmR4LwmLYfo nb8O7KulYZxu0dqxY8PeglSbgAc8jff+xx41+V5bhxdMZUT/oSTMv70Xs+ovmqX7 sBK5mPc4zcz28PmRxf1gQ5a69ouTFg+7xBm6+wluKjC5UItNSkYsUeXBvI6Kjf8X kjeO9t6eQ85iqR1SxD6KLhIE4eQ/gu3tCNCiUUTonA8kxJyHWtNmMjLs5Q7NtnmB h3MJo0Bjwf609ztIpAxp7+gRbkjRfLEWAsKyDrYzF2R9EQ06nxGwj05YsEYYXncw NnFutRNF/+CT0LYhEgGmbtrbnCcA3ZV6HmilsLHcDTPcdD1UyIhsx/qFxXD6Jawb 2MO8wyDuaHy171EXN9elUBLqG7+64mSuphj7fuHRKEf+ntvcao7CZpwyuVO1NA9m L84JltJ5MuK14Bm/bIJQE/0pduRJtMZkuKoInRuFtnT7vqAt03rb6SaKUwurjzIE 2nns1A0ddGcKQsn+zq0jyWAEPRVnLJTfk/hXjbUqk3Tw++h8r5GtvbdDrRU74r4h /1+7GR+cUUXCGG7HpuwthXCiXmhA9Vmz -----END CERTIFICATE----- cryptacular-1.2.5/src/test/resources/certs/test.example.com.crt000066400000000000000000000123001422604312300246410ustar00rootroot00000000000000Certificate: Data: Version: 3 (0x2) Serial Number: 1 (0x1) Signature Algorithm: sha256WithRSAEncryption Issuer: DC=com, DC=example, C=US, ST=New York, L=New York, O=Snake Oil Unlimited, CN=root.example.com Validity Not Before: Dec 4 16:50:56 2013 GMT Not After : Apr 21 16:50:56 2041 GMT Subject: C=US, ST=New York, O=Snake Oil Unlimited, CN=test.example.com Subject Public Key Info: Public Key Algorithm: rsaEncryption RSA Public Key: (2048 bit) Modulus (2048 bit): 00:dc:9e:9a:3e:fd:99:af:e3:ef:91:40:b1:6f:50: 4b:d3:7c:04:eb:34:cb:fc:99:2a:6d:fc:fe:74:8b: 62:0a:90:d0:d3:7f:79:5b:f0:f6:fe:76:3a:ee:9f: 09:e7:3e:3b:58:a6:dd:90:7f:16:d8:4d:85:64:1d: cf:44:7f:03:f5:57:74:86:55:c6:c3:d2:77:16:08: 3f:00:86:b8:b3:8e:12:1e:eb:9b:fe:b3:57:78:01: 11:be:26:07:54:04:be:fc:f7:ac:42:8c:62:be:12: 6c:3f:9d:29:5f:43:fd:d8:03:a8:b7:d5:a5:71:1f: e7:62:5a:39:4c:0b:e1:0f:0e:31:48:d8:38:61:ae: 48:be:24:f2:f4:35:fd:c7:da:aa:bf:a3:d2:22:46: 35:c2:f0:0b:38:00:7a:b6:71:ea:ff:10:b0:16:c6: 96:64:9f:55:8c:fe:cb:c9:a2:9a:79:99:8e:81:0e: af:0d:92:94:c0:9b:62:7e:55:4a:b1:06:1f:52:f0: a1:b0:54:c9:1d:b2:99:4b:74:14:80:bb:2e:63:b2: 24:e4:c7:20:3f:c2:ac:e4:ba:59:67:ec:45:fd:1e: 12:7d:3c:b5:da:ac:64:23:aa:8f:72:85:b2:29:c7: 61:f3:f7:d0:3b:54:7a:d4:53:6a:62:13:92:91:66: 28:75 Exponent: 65537 (0x10001) X509v3 extensions: X509v3 Basic Constraints: CA:FALSE Netscape Comment: OpenSSL Generated Certificate X509v3 Subject Key Identifier: 44:88:EF:79:2B:51:0B:16:31:FE:62:C3:2E:D3:26:F6:A8:EF:CD:A3 X509v3 Authority Key Identifier: keyid:7D:5A:81:08:93:BB:52:CF:2C:66:CD:D7:C1:47:B3:11:4B:01:43:6C DirName:/DC=com/DC=example/C=US/ST=New York/L=New York/O=Snake Oil Unlimited/CN=root.example.com serial:B9:3D:73:80:5C:40:DE:43 X509v3 Issuer Alternative Name: DNS:snake-1.example.com, DNS:snake-2.example.com Netscape CA Revocation Url: http://crl.example.com/ca-crl.pem Signature Algorithm: sha256WithRSAEncryption a3:f0:4a:d0:e6:2a:b2:f2:ab:4e:68:05:89:9d:d4:95:cc:7d: 7c:01:39:44:f0:9a:52:18:3c:49:78:3b:1b:95:00:7a:25:f0: c7:e6:25:a0:41:20:5f:86:8d:e3:c5:59:79:fe:6d:99:81:23: 40:a7:52:ed:b8:18:dd:f8:37:b9:5b:99:39:c2:6f:0f:8f:4a: 5f:c3:dd:b4:fd:ca:be:a2:5d:f5:56:8a:d6:f2:cd:ce:e7:92: 01:0f:4c:9c:a8:63:5a:2a:53:ca:ce:fe:88:87:f1:76:7e:6f: 0d:d0:55:b3:c2:db:03:13:f2:ea:88:0a:1b:a7:0e:cf:54:a9: 02:63:fc:1a:0f:94:40:68:46:f5:e2:4a:77:d1:fa:a7:35:d3: 0e:ba:17:1c:55:08:ca:e4:30:39:0f:c9:39:0b:e6:a7:f9:f9: 25:2f:8e:0f:88:81:5c:16:04:e0:0f:69:9b:21:87:4f:92:dd: ed:37:f6:a6:01:5d:7d:af:1d:fb:9f:53:67:2f:d2:8c:10:dd: d7:fb:16:ea:18:7f:47:28:d0:91:d7:1e:d7:25:a0:ed:0b:8c: 29:94:d5:a8:43:e8:74:f4:bf:f6:bd:d4:78:fe:c5:bd:5a:87: 53:27:ad:70:2c:77:61:4c:98:50:c9:c6:db:c8:d6:74:0e:1b: a9:04:2a:db -----BEGIN CERTIFICATE----- MIIFBjCCA+6gAwIBAgIBATANBgkqhkiG9w0BAQsFADCBmjETMBEGCgmSJomT8ixk ARkWA2NvbTEXMBUGCgmSJomT8ixkARkWB2V4YW1wbGUxCzAJBgNVBAYTAlVTMREw DwYDVQQIEwhOZXcgWW9yazERMA8GA1UEBxMITmV3IFlvcmsxHDAaBgNVBAoTE1Nu YWtlIE9pbCBVbmxpbWl0ZWQxGTAXBgNVBAMTEHJvb3QuZXhhbXBsZS5jb20wHhcN MTMxMjA0MTY1MDU2WhcNNDEwNDIxMTY1MDU2WjBZMQswCQYDVQQGEwJVUzERMA8G A1UECBMITmV3IFlvcmsxHDAaBgNVBAoTE1NuYWtlIE9pbCBVbmxpbWl0ZWQxGTAX BgNVBAMTEHRlc3QuZXhhbXBsZS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw ggEKAoIBAQDcnpo+/Zmv4++RQLFvUEvTfATrNMv8mSpt/P50i2IKkNDTf3lb8Pb+ djrunwnnPjtYpt2QfxbYTYVkHc9EfwP1V3SGVcbD0ncWCD8AhrizjhIe65v+s1d4 ARG+JgdUBL7896xCjGK+Emw/nSlfQ/3YA6i31aVxH+diWjlMC+EPDjFI2Dhhrki+ JPL0Nf3H2qq/o9IiRjXC8As4AHq2cer/ELAWxpZkn1WM/svJopp5mY6BDq8NkpTA m2J+VUqxBh9S8KGwVMkdsplLdBSAuy5jsiTkxyA/wqzkulln7EX9HhJ9PLXarGQj qo9yhbIpx2Hz99A7VHrUU2piE5KRZih1AgMBAAGjggGVMIIBkTAJBgNVHRMEAjAA MCwGCWCGSAGG+EIBDQQfFh1PcGVuU1NMIEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTAd BgNVHQ4EFgQURIjveStRCxYx/mLDLtMm9qjvzaMwgc8GA1UdIwSBxzCBxIAUfVqB CJO7Us8sZs3XwUezEUsBQ2yhgaCkgZ0wgZoxEzARBgoJkiaJk/IsZAEZFgNjb20x FzAVBgoJkiaJk/IsZAEZFgdleGFtcGxlMQswCQYDVQQGEwJVUzERMA8GA1UECBMI TmV3IFlvcmsxETAPBgNVBAcTCE5ldyBZb3JrMRwwGgYDVQQKExNTbmFrZSBPaWwg VW5saW1pdGVkMRkwFwYDVQQDExByb290LmV4YW1wbGUuY29tggkAuT1zgFxA3kMw MwYDVR0SBCwwKoITc25ha2UtMS5leGFtcGxlLmNvbYITc25ha2UtMi5leGFtcGxl LmNvbTAwBglghkgBhvhCAQQEIxYhaHR0cDovL2NybC5leGFtcGxlLmNvbS9jYS1j cmwucGVtMA0GCSqGSIb3DQEBCwUAA4IBAQCj8ErQ5iqy8qtOaAWJndSVzH18ATlE 8JpSGDxJeDsblQB6JfDH5iWgQSBfho3jxVl5/m2ZgSNAp1LtuBjd+De5W5k5wm8P j0pfw920/cq+ol31VorW8s3O55IBD0ycqGNaKlPKzv6Ih/F2fm8N0FWzwtsDE/Lq iAobpw7PVKkCY/waD5RAaEb14kp30fqnNdMOuhccVQjK5DA5D8k5C+an+fklL44P iIFcFgTgD2mbIYdPkt3tN/amAV19rx37n1NnL9KMEN3X+xbqGH9HKNCR1x7XJaDt C4wplNWoQ+h09L/2vdR4/sW9WodTJ61wLHdhTJhQycbbyNZ0DhupBCrb -----END CERTIFICATE----- cryptacular-1.2.5/src/test/resources/certs/thawte-premium-server-ca.crt000066400000000000000000000022031422604312300263110ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIDJzCCApCgAwIBAgIBATANBgkqhkiG9w0BAQQFADCBzjELMAkGA1UEBhMCWkEx FTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYD VQQKExRUaGF3dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlv biBTZXJ2aWNlcyBEaXZpc2lvbjEhMB8GA1UEAxMYVGhhd3RlIFByZW1pdW0gU2Vy dmVyIENBMSgwJgYJKoZIhvcNAQkBFhlwcmVtaXVtLXNlcnZlckB0aGF3dGUuY29t MB4XDTk2MDgwMTAwMDAwMFoXDTIwMTIzMTIzNTk1OVowgc4xCzAJBgNVBAYTAlpB MRUwEwYDVQQIEwxXZXN0ZXJuIENhcGUxEjAQBgNVBAcTCUNhcGUgVG93bjEdMBsG A1UEChMUVGhhd3RlIENvbnN1bHRpbmcgY2MxKDAmBgNVBAsTH0NlcnRpZmljYXRp b24gU2VydmljZXMgRGl2aXNpb24xITAfBgNVBAMTGFRoYXd0ZSBQcmVtaXVtIFNl cnZlciBDQTEoMCYGCSqGSIb3DQEJARYZcHJlbWl1bS1zZXJ2ZXJAdGhhd3RlLmNv bTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA0jY2aovXwlue2oFBYo847kkE VdbQ7xwblRZH7xhINTpS9CtqBo87L+pW46+GjZ4X9560ZXUCTe/LCaIhUdib0GfQ ug2SBhRz1JPLlyoAnFxODLz6FVL88kRu2hFKbgifLy3j+ao6hnO2RlNYyIkFvYMR uHM/qgeN9EJN50CdHDcCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG 9w0BAQQFAAOBgQAmSCwWwlj66BZ0DKqqX1Q/8tfJeGBeXm43YyJ3Nn6yF8Q0ufUI hfzJATj/Tb7yFkJD57taRvvBxhEf8UqwKEbJw8RCfbz6q1lu1bdRiBHjpIUZa4JM pAwSremkrj/xw0llmozFyD4lt5SZu5IycQfwhl7tUCemDaYj+bvLpgcUQg== -----END CERTIFICATE----- cryptacular-1.2.5/src/test/resources/certs/unknown-dn-attr.crt000066400000000000000000000026031422604312300245260ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIID5jCCAs6gAwIBAgIJAKezwvQ9w/frMA0GCSqGSIb3DQEBBQUAMFUxETAPBgNV BAMTCG1hcnppcGFuMRIwEAYEKgMEBRMIbm9uc2Vuc2UxFzAVBgoJkiaJk/IsZAEZ FgdleGFtcGxlMRMwEQYKCZImiZPyLGQBGRYDb3JnMB4XDTE0MTExOTE2Mzg1MVoX DTE0MTIxOTE2Mzg1MVowVTERMA8GA1UEAxMIbWFyemlwYW4xEjAQBgQqAwQFEwhu b25zZW5zZTEXMBUGCgmSJomT8ixkARkWB2V4YW1wbGUxEzARBgoJkiaJk/IsZAEZ FgNvcmcwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDJqxu5wkvp2xIV iqPYaqPILIojitnspRsPHBe7JjPW+rDHx68RNzkht/uCOTvvDPYvKbf7aZyaFQnT QBQMaWqX1FkwcMRoVHeJpvi8pS5pyuvcu3kpS3U3aT7t6Joi/qhPBZMc9iu8Pe4j Icf8CPQUSCMJoSl1llbM0EBxqxTa9vKTsryt1xkVPM0Of1i5RpC4Y9gipSyKffWH 8M0RX2p2iVu79te0GAwDBmKw2lNLkPodDj8yF78CRnJJw07R8kMVoS0Hi91Sx6NE hbmvc+zijpF2/RFsOjDBh3Im6V6ejnDwFu8+5P/kuL04nL1I0lG5Urv0js3Jlgn3 6DuYomXfAgMBAAGjgbgwgbUwHQYDVR0OBBYEFDjmj8OUyhybOlxItbtd7dKB61TQ MIGFBgNVHSMEfjB8gBQ45o/DlMocmzpcSLW7Xe3SgetU0KFZpFcwVTERMA8GA1UE AxMIbWFyemlwYW4xEjAQBgQqAwQFEwhub25zZW5zZTEXMBUGCgmSJomT8ixkARkW B2V4YW1wbGUxEzARBgoJkiaJk/IsZAEZFgNvcmeCCQCns8L0PcP36zAMBgNVHRME BTADAQH/MA0GCSqGSIb3DQEBBQUAA4IBAQB7gDp+vpIFNoAACztjrr5UXeRwdHYS L1J5FepfBcsjvlx1rwDWS7B0GiHxO7RRG4H/NzErRX6Jnoks4qz3pdX4sT358hn+ 7YeSnQ8pnl8WRWqrk968YJtn4GKdVIZcH2szuzJ+cuvsnfSBb9Hn9OpLe7PU8naS b7xWclvWXS87nWvR4i8Yq3uhBNIl70NON3es7SledzdvySWJ8HpKW2zxdFqAGKOY VGUROtBKMrjc8Or2A+ocApAVMfm5HpGrVJvipRCenb9VgLTlBDA32lZVnPDapHtP RhBSt1uuroqcofUod+MHoy2LDtYIch66iz9CGs4gZ9xmvFSdBvsMp07I -----END CERTIFICATE----- cryptacular-1.2.5/src/test/resources/certs/vtgsca_chain.pem000066400000000000000000000160551422604312300241100ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIG3jCCBMagAwIBAgIIPHK7keZq/ZUwDQYJKoZIhvcNAQEFBQAwZTELMAkGA1UE BhMCVVMxFjAUBgNVBAoTDVZpcmdpbmlhIFRlY2gxFzAVBgNVBAsTDkdsb2JhbCBS b290IENBMSUwIwYDVQQDExxWaXJnaW5pYSBUZWNoIEdsb2JhbCBSb290IENBMB4X DTExMDExODE2MzYyMVoXDTIwMTExODEwMDAwMFowaTEnMCUGA1UEAwweVmlyZ2lu aWEgVGVjaCBHbG9iYWwgU2VydmVyIENBMRkwFwYDVQQLDBBHbG9iYWwgU2VydmVy IENBMRYwFAYDVQQKDA1WaXJnaW5pYSBUZWNoMQswCQYDVQQGEwJVUzCCAiIwDQYJ KoZIhvcNAQEBBQADggIPADCCAgoCggIBALZZbbiCLqUuFETVAoVvKlVqoGq4Ex7l gWR3lhZrDJo2XN7Q8rE6O9R0u53Tb39UuFiG+rJFgevykZq/bk06xRxtvpo0dzEn 0Xt7e2RjLLWAwDMb6WJjCJ9XvHJZfP6z1XXSpcohQetrUf7oYP2twpOmQbRBqvjz RkCcz3u5iRUgGn3f75LWkFPjeNEdLoWWF8iTp0QcTbQ8uPiSJFkQMxXkZdTsqUsF Kq54tEh75Lt5OHLrpcbwe2Rq3J8NYKVp6mGlpVRL2hmbZaEIvZkhj52Am1uPb5lX h1zpLfwk6vZwuo+Kmsv9sWi331DUEEWagDvtP2AhQUFmfGphMx78me0eMqASOk8I 2FN0EnrXl5p4wGiXw2tK65UKqZUz8wwDgNbbA/UqNqgxC0OFaZwjkMei3pI8p4uA rgdZDhyL3V6zA1byQP3HAmEdKNXqvAE8j30I4xwdyu3m14jjMzmvTSZcn2HTqESi 6UC5yuDEC8pSmCdUK5VdbbI1s63uQvkzLUxXHhhgiUcOY9PzVLT9edw+ymwoYoVC IlqrG7i/o+CIy5t7lE7yQ9We8XnR5d7cbtxHgeGe/dfCmzqvZpAxiV8f0bFMdB+c zdawPVaoL4DySDmVMO7iY8jBtk0vB05xPgOmhFJkkMMp2eVYcNVIzxTqJAVM45Gu dBq8uNm8xUY9AgMBAAGjggGMMIIBiDBSBggrBgEFBQcBAQRGMEQwQgYIKwYBBQUH MAKGNmh0dHA6Ly93d3cucGtpLnZ0LmVkdS9nbG9iYWxyb290L2NhY2VydC9nbG9i YWxyb290LmNydDAdBgNVHQ4EFgQUCyOn9eYxh71E5K/HEMx0mh1H8fYwEgYDVR0T AQH/BAgwBgEB/wIBADAfBgNVHSMEGDAWgBR4w+1F/pkMoulXrlhSWS/yr8TAYjCB jAYDVR0gBIGEMIGBMA4GDCsGAQQBtGgFAgICATAOBgwrBgEEAbRoBQICAQEwDgYM KwYBBAG0aAUCAgQBMD8GDCsGAQQBtGgFAgIFATAvMC0GCCsGAQUFBwIBFiFodHRw Oi8vd3d3LnBraS52dC5lZHUvcm9vdGNhL2Nwcy8wDgYMKwYBBAG0aAUCAgMBMD8G A1UdHwQ4MDYwNKAyoDCGLmh0dHA6Ly93d3cucGtpLnZ0LmVkdS9nbG9iYWxyb290 L2NybC9jYWNybC5jcmwwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBBQUAA4IC AQBgU3s9/+KRBFdjEUbWcMWUAhEqWWWCkuvSwyZzEoWnkwbisTBwXzvkiiuKPdH6 BhSu/IL8CFaRyovsjU+Qh/TknYUA8E9NmqHssuf5QA2haHI72mum7MY9CXPq0HNy tOesWKk6Ci5L59DdwrQ/DZ9kkwzYEzb3noUSOGmiTqwGHF9+hiJdlDPEqq4Az33B E1HOUH/YLjvBFx6HXFa0ZdqJWJ9sLrX2odTdHmLt9rAOTXCZOvowCud1Vw2BIdGU qnJo1f3oZmvPH0zkgEzwK3HYWEwz6nrIMlDDN2NqIoyqdAd0+R+3I+N0y9ceh/0A BAzR4fvTTSEexVr+ZQIU78E8PNt4GuQ5usFaOElrn/sivWXWRj53g+efJlEUcdRD AZqEZl5YuSRn2GTIFNRaOkASggyGzTTdRinWiqUWfxZu4C5WxNZztmWaUKp2VCvQ u9Bxsgr8ZTZy/rPNvy985jLbm4n8LB6J590xb/oAzWdp02Ge5PVLJqRLVQjcEUtg 8EPxtXj1h1eKTVDdxkfQGaXbAOLQTyO4IsDmYbpPoAtKTpNBeflZo9qDjUSekY4b Y/zZpp//4TqVgVvpNLsA+KY4PHWk4iLwgzE6EZtjeLUln+nTck9xlGzwYjJQy0De bKEd1GaYa6ofxDz/IJU8zu5P0aSi6Bd1iA0jJTl+aF80CQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF3TCCBMWgAwIBAgILBAAAAAABLF5/HXYwDQYJKoZIhvcNAQEFBQAwcTEoMCYG A1UEAxMfR2xvYmFsU2lnbiBSb290U2lnbiBQYXJ0bmVycyBDQTEdMBsGA1UECxMU Um9vdFNpZ24gUGFydG5lcnMgQ0ExGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2Ex CzAJBgNVBAYTAkJFMB4XDTEwMTExODEwMDAwMFoXDTIwMTExODEwMDAwMFowZTEL MAkGA1UEBhMCVVMxFjAUBgNVBAoTDVZpcmdpbmlhIFRlY2gxFzAVBgNVBAsTDkds b2JhbCBSb290IENBMSUwIwYDVQQDExxWaXJnaW5pYSBUZWNoIEdsb2JhbCBSb290 IENBMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAot80+Dl5XoWNCsPy MG0JTJonOCeDwh92+XJ9mza+n+gMCjmXzmqzoDSgI0RwVMPMAizEyRZc044GBvw6 blQHIlTTAWmxr904ABfgRTPnt5o9gGk55VcezfYZ0zT2I8OPEbPjOyNiJkNhKc7j ibef9C5DAxqYV2+kcwnx3edqnl5zHRK3EFAvHHoHVvrkfgd92hPqJO4XiIF4LSaX ZDDwSnHlJfpjJS3Qez2fl2skp6IV08Za3T5wZ8et4bPXpQiNsMTyOtPpGff9Qd2M wzlecgXYPqa117m2l4RGtapHQ4ei3mjjpbz6yEaT8O1wqeCItsG4roSDyb865LUX G719T0UZkr8HPyWPtglMURERsc03x/gLOE/1oSnoHU+9z0g6wMyOioBrkXKHdJoL oZklV3CddVJF+3AbjXUw9MyYGpKonJ6KC2M6OyvzMKpgvo3W3VIr7YdyBtQRsF4Z bQHSkTi3lce+HmXxGB03/w0oyxSbC31wQaE7lcDzq8TIcEl5w6YrR1KfaqvruO4g 8a+SnzeA2rz8K8ya19Y/0WWK8SsWLzLe/TnNO0sOt5MqynBbjuiQzxyT5nJQiz3O Enm1yS4ipImrtmINTpMv+/dWHcRkqCjDLe5nhphF3WaE9T2ELsqQUES5mYanEG3/ 1I0hUdxOx1hnsvuxsvjWTCVbJdUCAwEAAaOCAYAwggF8MA4GA1UdDwEB/wQEAwIB BjASBgNVHRMBAf8ECDAGAQH/AgEBMB0GA1UdDgQWBBR4w+1F/pkMoulXrlhSWS/y r8TAYjB8BgNVHSAEdTBzMHEGCSsGAQQBoDIBPDBkMDEGCCsGAQUFBwIBFiVodHRw Oi8vd3d3Lmdsb2JhbHNpZ24uY29tL3JlcG9zaXRvcnkvMC8GCCsGAQUFBwICMCMa IWh0dHA6Ly93d3cucGtpLnZ0LmVkdS9yb290Y2EvY3BzLzA/BgNVHR8EODA2MDSg MqAwhi5odHRwOi8vY3JsLmdsb2JhbHNpZ24ubmV0L1Jvb3RTaWduUGFydG5lcnMu Y3JsMFcGCCsGAQUFBwEBBEswSTBHBggrBgEFBQcwAoY7aHR0cDovL3NlY3VyZS5n bG9iYWxzaWduLm5ldC9jYWNlcnQvUm9vdFNpZ25QYXJ0bmVycy1SMS5jcnQwHwYD VR0jBBgwFoAUVoTstXGl52PY21EE1vrm8EhSSc4wDQYJKoZIhvcNAQEFBQADggEB AHyR8iWGLs9Wzs+vELu8d0O1X0NYSpfupMP/TpkpyuAyFGl52TnVJvi7p46D4U/H sm7WhEnFm9g24Kv7OCoccS5ST41QZR56AivFXcJh0zXuWpJ8lJGFnvtDrzK2vo9A whFnZHiq99gfBOZmpgxqi5+/B5nt4c7bX2fD+JQrUATjuyji+32qdKb88otOtmY3 G2ymLw+t33WdpBi+E3TSsELbDrBoJSJRHxGrArDRXZBdSQyKcOJINH6o3d2gAnyU idbweTuj7eftXM5VBJpQ/r4TMtfSx8RQOnmftEXWLxVv7xCpy+DegB7Jmz6xgvZ9 LYeKy8z9lQXkXBBpnStGGsg= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIID5zCCAs+gAwIBAgILBAAAAAABFUtaxacwDQYJKoZIhvcNAQEFBQAwVzELMAkG A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw0wMzEyMTYxMzAw MDBaFw0yODAxMjgxMTAwMDBaMHExKDAmBgNVBAMTH0dsb2JhbFNpZ24gUm9vdFNp Z24gUGFydG5lcnMgQ0ExHTAbBgNVBAsTFFJvb3RTaWduIFBhcnRuZXJzIENBMRkw FwYDVQQKExBHbG9iYWxTaWduIG52LXNhMQswCQYDVQQGEwJCRTCCASIwDQYJKoZI hvcNAQEBBQADggEPADCCAQoCggEBAL3vMPEw8TSpiWV3TUanjZD9rk+OyigXulnj qJIKRQMqio/lCVBVUoHwo5Gx2RIqgfbCAxw8gsByzfGnANf1VJwKR+6alUGSjqCt CT3T66J0rZ8ZIAm2faZeNZ9POWoDtYqtH5Ziaxe5q4dg1V1t2ZLJ0BOu1IjZUKhE kQSw6kfqX7LtBMHXAXwh+MRxI/xrTGVEM8ONHebSZhxSKUbEBucLNfBZAWYAic+c 43t4qlPi7qw1lef9XddClJXTGm4xVUfX663HTJ9UcYMaF8j5585YAfQ2v64/WZ9l fEAHXHMgNKISw0n0aEBpHonghek6t5dju0ewOWtBAH71S7h/4yECAwEAAaOBmTCB ljAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUVoTs tXGl52PY21EE1vrm8EhSSc4wMwYDVR0fBCwwKjAooCagJIYiaHR0cDovL2NybC5n bG9iYWxzaWduLm5ldC9Sb290LmNybDAfBgNVHSMEGDAWgBRge2YaRQ2XyolQL30E zTSo//z9SzANBgkqhkiG9w0BAQUFAAOCAQEAzeN0ltyXbKD5p2QRBKst9isZPl/R xbiw5Ijr9WLDCfJXza7b2o2kUOxkJ9ivz/BE+0DJc1i5G02aZf5bVq/CltFmJyS7 lToQ+cO3jmPhA1++FLfHUz/C19/6NisbYPNo4713x0CDcqpOhWu7M8CcdF7gu3JT 66Ra4nqoWPZJugW97gBm8cThETDunuYnd6I2fA3FoNdMhs1CdiVkOy1xFKIZS/ZK IV159Qmxa8xiP6uTrJ28t4lqRr0Ewf6DFpzuDSm3t6Rm4OvMIrfE0uDaJDl5E5Px 4dTMhbD6kRoWFMpj+z63jhFxBPwF2DbBKv5UAlLuOWCQwmnjYEa6AyJzCw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkG A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAw MDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i YWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYDVQQDExJHbG9iYWxT aWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDaDuaZ jc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavp xy0Sy6scTHAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp 1Wrjsok6Vjk4bwY8iGlbKk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdG snUOhugZitVtbNV4FpWi6cgKOOvyJBNPc1STE4U6G7weNLWLBYy5d4ux2x8gkasJ U26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrXgzT/LCrBbBlDSgeF59N8 9iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8E BTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0B AQUFAAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOz yj1hTdNGCbM+w6DjY1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE 38NflNUVyRRBnMRddWQVDf9VMOyGj/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymP AbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhHhm4qxFYxldBniYUr+WymXUad DKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveCX4XSQRjbgbME HMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A== -----END CERTIFICATE----- cryptacular-1.2.5/src/test/resources/certs/vtuca_chain.p7b000066400000000000000000000111021422604312300236360ustar00rootroot00000000000000-----BEGIN PKCS7----- MIINVwYJKoZIhvcNAQcCoIINSDCCDUQCAQExADALBgkqhkiG9w0BBwGggg0qMIIG 8TCCBNmgAwIBAgIBBTANBgkqhkiG9w0BAQUFADBVMQswCQYDVQQGEwJVUzERMA8G A1UECBMIVmlyZ2luaWExEzARBgNVBAcTCkJsYWNrc2J1cmcxHjAcBgNVBAoTFVZp cmdpbmlhIFRlY2ggUm9vdCBDQTAeFw0wNjA5MjAxNjI4MzZaFw0xNjA5MTcxNjI4 MzZaMIGUMRMwEQYKCZImiZPyLGQBGRMDZWR1MRIwEAYKCZImiZPyLGQBGRMCdnQx CzAJBgNVBAYTAlVTMTwwOgYDVQQKEzNWaXJnaW5pYSBQb2x5dGVjaG5pYyBJbnN0 aXR1dGUgYW5kIFN0YXRlIFVuaXZlcnNpdHkxHjAcBgNVBAMTFVZpcmdpbmlhIFRl Y2ggVXNlciBDQTCCAiAwDQYJKoZIhvcNAQEBBQADggINADCCAggCggIBALtuDADJ vOwqLAdiorNhINDADF6T3/xUGKGRiIGmjgy2COLGlxFHAgq8Hi8pPk3CzhUbBDia r1sFo0BfzozoticTzlF2tIuftSTMCbQWPB0bPZlYp5zSt7WBgHhfVeBnWrgn5eVk CJEfiwPjtOtlNvCykFKgM+4OTfC+ocCZwWmLR1PBmJ+CAf12xBbKoDIhPDOmTWOg lu85oJXPTPwd8caLHR4cKeznuxq+i8Y0uqgtXc6+nhWZ6zUcXO65Q0y5aRwJgt2L 8Q6Pr34qFWR3GF+e6iIAY4UT951X5UdyfvSSNjN5BUhJv8n1mzHOqpdyiZf5qDEt DNFYGx/o9sXVcqaLR0S61Z7UkcZQKZLZQDwZVthT9i69+N2D1ckaME9dto0ApIgr gz0sUneg3hVs8un1bpXtJcsGfuUgWIp+qyjVZZQYN71wYXZ+HPEkmbRuXdrXEvC5 63bL7gT/2/m5UqWoW3u8yaAO+DcuY9w0eh37mapsF2IuD3q4htFAM4cVUSCa0AQl PdXnhu2JM4VR4S4aKkHCQQMS1lTr9A3DEdEvoqAeNNOLhP430CrULChYf1/0FGiu PV1SADe6vrXf8y87W7RsWhuTFLyHxRq4eBHzBVnPrHk1ac8XslxcXz1qPm+Nshfa sGX26wHSbXJ8lddnkUPQKiOFrGnCtNGoHdntAgEDo4IBjDCCAYgwDwYDVR0TAQH/ BAUwAwEB/zALBgNVHQ8EBAMCAQYwHQYDVR0OBBYEFN67bqLJNHXY8VeVeRD5A8DU aQqMMH0GA1UdIwR2MHSAFESRFC84mijaPkomPJiAo/z3iG2noVmkVzBVMQswCQYD VQQGEwJVUzERMA8GA1UECBMIVmlyZ2luaWExEzARBgNVBAcTCkJsYWNrc2J1cmcx HjAcBgNVBAoTFVZpcmdpbmlhIFRlY2ggUm9vdCBDQYIBADA7BgNVHR8ENDAyMDCg LqAshipodHRwOi8vd3d3LnBraS52dC5lZHUvcm9vdGNhL2NybC9jYWNybC5jcmww gYwGA1UdIASBhDCBgTAOBgwrBgEEAbRoBQICAQEwDgYMKwYBBAG0aAUCAgIBMA4G DCsGAQQBtGgFAgIDATAOBgwrBgEEAbRoBQICBAEwPwYMKwYBBAG0aAUCAgUBMC8w LQYIKwYBBQUHAgEWIWh0dHA6Ly93d3cucGtpLnZ0LmVkdS9yb290Y2EvY3BzLzAN BgkqhkiG9w0BAQUFAAOCAgEAY1QvqZ9ozwQPrPQmqz2XhXCCDZxriy0dapk537wE SYq+D4Ptkpuu+P8HDSi0j6QaksM6h7otm4k1znD1fcGt7uo2YzDoO1hyORjan4ZK FgsR906LgexvTreYGSi1+4VKcfALDkqd/snkoPMFI3/KQnEoKbqwCXVQL908WrD6 PH8gdNb5M8Es+TzH49iA4J+jQrE6CqVMAq2e/QwyC7EJ3yUHknBV0hpaWEvkUtty XxFaF3ZVfOo0j2xxXcCihR4PGyUHlkPj5U3ggjyDZ7TTS0mtwmluNuhaJva2trW6 NbscmZ0vdoyQLxjGVkBeeEFyNcm4OPMEc3uMzvhacxvN4NJF6Mhyhj+Sc/97KTYU CZNPiP9fE8Ev6klgjbf6AA9ARHARDWpQ/F7CbN710Ft2iHZb0uldzZRMBevW3M4y 9Q62YQtr7WhuJ+FZFA3JnjJjOfYaR8c6zOXsWiyPFQ8Eq3qMdcO9V4UmDKeYK0hD YI6BHpoKXNEikf7ygwKVVmOjLzSJI1G/knj9UffiusmlSQ7Cx5nz5HwciBtAxYp1 6IyL0YNi1Con8YbB0EKlW8LS9+4d1R+cKtx/tPTQLJv9jjqlp/sw+NdDEkJ0Q4YA TGJXklx3Q1QpyuA1TiI+7CXEyO9zkPQVptXAzB+kePb/TvwtaDI71LwYjg52d7nb /wgwggYxMIIEGaADAgECAgEAMA0GCSqGSIb3DQEBBQUAMFUxCzAJBgNVBAYTAlVT MREwDwYDVQQIEwhWaXJnaW5pYTETMBEGA1UEBxMKQmxhY2tzYnVyZzEeMBwGA1UE ChMVVmlyZ2luaWEgVGVjaCBSb290IENBMB4XDTAzMDQxMDE5Mjc0OVoXDTMzMDQw MjE5Mjc0OVowVTELMAkGA1UEBhMCVVMxETAPBgNVBAgTCFZpcmdpbmlhMRMwEQYD VQQHEwpCbGFja3NidXJnMR4wHAYDVQQKExVWaXJnaW5pYSBUZWNoIFJvb3QgQ0Ew ggIgMA0GCSqGSIb3DQEBAQUAA4ICDQAwggIIAoICAQCgRDSdz9FCKV9+KKohQDcO tcANOrvANxnCPJMsykQCRvGTKlhoSxhjApRkwJn4a60130Alm4AUD3iQANUYUnFq mCbjmmhieFTNGZkMBMVOIRIsupcMZLZsbYqSJSykxonejb9/WlTDEahVXh87p349 9Pc/m/pZjfUjYAYrBzR/QwuFNq8eLdOlDcwlZS/PXfhtL5LjWm07DrAzKwUiUUCS +IZrQqbquHNYUB+16IwtKv9ceInMwN+8nIBmhYPWQjKaX27Zvrj1x+FgpkXdv9A/ b3ilioJZafiLx7/q2V9A01zb6uU18Sjxj3bqPlXXl7cK7BenQ8dDEwV/5DcCnaoQ ZJDT1PYYXiqdUoGgsFypZbuMZ0f2+6pKGI3nmiz5vOpmKvrE7+aX70gyNa0irQJM 7OYailArddrOd7ostPZRMX1wcRrBoXh6IvTTMohrSo+yKVd9TIW60IebN0GPJZa/ P9JUbsfYH1RjUOUOtvH7cTAYr9mNPaKiW4NpHVEz8o+RE24kifa46c2+cMe5PFR9 mVXsiwdaFEJ4BhF4DRTMfGU7R19hDR7vr5FiqPU36i5jLGTgAmmzrJWPTmi42l79 65UxNyL4GjdJPPZzFilKw2Yk/B/7Kky+fkpdyBqnwtHRr5X/u7gW1w3eYnqIUa/5 askh5S5yqD8u64e1lLBXCQIBA6OCAQwwggEIMA8GA1UdEwEB/wQFMAMBAf8wHQYD VR0OBBYEFESRFC84mijaPkomPJiAo/z3iG2nMH0GA1UdIwR2MHSAFESRFC84mija PkomPJiAo/z3iG2noVmkVzBVMQswCQYDVQQGEwJVUzERMA8GA1UECBMIVmlyZ2lu aWExEzARBgNVBAcTCkJsYWNrc2J1cmcxHjAcBgNVBAoTFVZpcmdpbmlhIFRlY2gg Um9vdCBDQYIBADALBgNVHQ8EBAMCAQYwSgYDVR0gBEMwQTA/BgwrBgEEAbRoBQIB AQEwLzAtBggrBgEFBQcCARYhaHR0cDovL3d3dy5wa2kudnQuZWR1L3Jvb3RjYS9j cHMvMA0GCSqGSIb3DQEBBQUAA4ICAQB9k2F2LPLGh0BN9l2ER3sYSpWwEGEfWCrB Nl2Hhh75qmIFhOGHLiEdnbG87v/1fv2phIiFkSliq2s8LZJJJb6uMpKjKWmovSaf iQWXMfzm/266M6W7cxwSwymuaVZLIDqpfC0BsiIRixbuWB6qIy3wcBjTC4t4mBpV b//zjpk18TrbFbw5ee/ISuI/LMw86XbvKlhfU6Q4l4WGOyhUPw2lpVcmaKNkiVKe AG1CSa9L4XTCz7VJ0dm/kJXwfzw4cnRerZRjRBTKOa1geMvP5eG7mdx5bLwEIC4W qpxQ0a4S63NkMZShMzouXOiwwZk//DHOKrPTAtbEfrQ0cowL0cwmq5rrGmcqQQbK Dlu9GJO9aFSlVz0EpKtn4RazRe9aJwVb1m8u/uoZUQQDKDgVp4SNQnMlgYexyYRP E4RBRv6azJvJw19izG9m18iCaAb3oCHcmuAHCKr8/3nqsvdoWqrDMETuuxaLW2F4 E/rWDHECGYmAbh8IMmoLY1cIB5hH1Qy6yjM4jfiz9bMQdIZ7vhM1JCSkrfUnBbOV 6VipDH/YaMPnnmZ5Ay8gPRMm/iS7c5SQP/HcYcmvWAmKY/JTUeBTnSAF34hPBl0G 6YwvGUgcbd556rqzS6498+5mEVTWE/jC0NzdHzrI2uTFiGFZMhaJgHMatOZixCB9 IOE8OVlB9qEAMQA= -----END PKCS7----- cryptacular-1.2.5/src/test/resources/keys/000077500000000000000000000000001422604312300206005ustar00rootroot00000000000000cryptacular-1.2.5/src/test/resources/keys/aes-128.key000066400000000000000000000000201422604312300223620ustar00rootroot00000000000000|ˢoU2'>cryptacular-1.2.5/src/test/resources/keys/dsa-openssl-des3.pem000066400000000000000000000013501422604312300243660ustar00rootroot00000000000000-----BEGIN DSA PRIVATE KEY----- Proc-Type: 4,ENCRYPTED DEK-Info: DES-EDE3-CBC,5E562BC405BB14E8 SUa/8UvU4GuanQJU8F2HQpizTuDdn93kk/h0HlQL8d9YFF1eHqxRfwzTWbw99/n3 VZ6WC5xaP3w0nxD034Za56ujKL5GcmCQsNuVljFlOUqoFxDIUfxkFx5lX/zXIC8w 3jSnYA2ga29bA+bUTVGuCBuzyqumh3zdpMXx2LpJGtTh7DGcDbCu5GBPF3SPHUhi iCXubJJJLuB15siChYVx4+w+74n2Y1Ga+FN6CL1svX+cpnMIH8jhlPQNmNySlEbW yBaaXUWoCFUeZZXt4rvzkTnXm5idKr0zYwuCp871rxQj8g2zqy8WGoJmjIj08vjD hSO0lRSlg8LQY2zNiv/D+PyXoODoS5AcSExjFsHs8RGynndgiGV2HpmgJ3d3Db/M ZdvCsHf8ldwmHhIAwjVbO30b93syaVhV+/O+pQ16XjEawgS9Rzz1POrAOr3/C8as WsYxT+5LDI6TYq+ng2JTiHx10VfSNbHZddXgt0E2utIt6kd7GKDbGBGKes8DJjqI 8LrmVafdfBSea2R5i03YAMzOIpTxgyeJsiK0THm+XtjpTZ1yLSYN5ee9uvOz9TQd 0MlWsFwB+9tFlLAV7J0yjKM4kzykrVHS -----END DSA PRIVATE KEY----- cryptacular-1.2.5/src/test/resources/keys/dsa-openssl-nopass.der000066400000000000000000000007001422604312300250220ustar00rootroot000000000000000륉aTe㮵'ArEo@U}Øߜ Tz&ՈQ|QƁt.7ezdFo>yu٫&鸘]KyQ*lb{D&x;pL@I9̪^ญVK+I9YZ6qz 8Vgކơk E VOw ȧ&?cV&3b~FpSg{%r.<6[ /p{% cU;s\*Jyzt;ޠ`-=З \߁u9[5UnKFF"|O1tm\[gT)>Iӄ0Ƶ0oKK 2?VȻcryptacular-1.2.5/src/test/resources/keys/dsa-openssl-nopass.pem000066400000000000000000000012401422604312300250310ustar00rootroot00000000000000-----BEGIN DSA PRIVATE KEY----- MIIBvAIBAAKBgQDrpYnxvgBhgVRlhI7pxuOuta8nQe3hckXx828FQFWj1NB98xXD mN+c9Zej5OGQDVR6u4Qm1YiQUe18q5GCmlHGgdJ0jy4IN71ljprxqobkerVkRm8+ H8h5dbqwkZPZqybpuJgCXdzpS7oAsriKqM7GFLbyeZpRnr4q9c5sYpynewIVAO3w RMkmD+d4OxSzpXBMroSI70ABAoGASfW2qBs59MyqXrXguI32xlbiqxZLK9nnmNAB STnk7chZAp1aqzZxeu+HjdUQDsANrc84VmfehtABrsfGoZhrDUW4/6mlEwzUVq+w TwSLw3fvC6TIp+Am+Y+HPwO7jmPuVsYVJt0zYn7ngUaIcIdTZ3sWEKqXJXLk0QP6 LoC1+PICgYEA6Tw2khtb1g0vcHu6JRgggWPZVTuj/HOH3FyjufsfHogWKrlKebZ6 hnQ73qAcEgLLYKctPdCX6wnpXN+BsQGYdTkc0FsUNZD4VW5L5kaWRiLVfE8x55wX dMZtXKWqg1vL6aXYZw7RFe9U9Ck+/AG90knThDC+xrX2FTDm6uC25rkCFQDi5v1v S/zsr0up+AudMj9WvQTIuw== -----END DSA PRIVATE KEY----- cryptacular-1.2.5/src/test/resources/keys/dsa-pkcs8-nopass.der000066400000000000000000000005171422604312300243750ustar00rootroot000000000000000K0+*H80륉aTe㮵'ArEo@U}Øߜ Tz&ՈQ|QƁt.7ezdFo>yu٫&鸘]KyQ*lb{D&x;pL@I9̪^ญVK+I9YZ6qz 8Vgކơk E VOw ȧ&?cV&3b~FpSg{%r.oKK 2?VȻcryptacular-1.2.5/src/test/resources/keys/dsa-pkcs8-nopass.pem000066400000000000000000000007751422604312300244120ustar00rootroot00000000000000-----BEGIN PRIVATE KEY----- MIIBSwIBADCCASsGByqGSM44BAEwggEeAoGBAOulifG+AGGBVGWEjunG4661rydB 7eFyRfHzbwVAVaPU0H3zFcOY35z1l6Pk4ZANVHq7hCbViJBR7XyrkYKaUcaB0nSP Lgg3vWWOmvGqhuR6tWRGbz4fyHl1urCRk9mrJum4mAJd3OlLugCyuIqozsYUtvJ5 mlGevir1zmxinKd7AhUA7fBEySYP53g7FLOlcEyuhIjvQAECgYBJ9baoGzn0zKpe teC4jfbGVuKrFksr2eeY0AFJOeTtyFkCnVqrNnF674eN1RAOwA2tzzhWZ96G0AGu x8ahmGsNRbj/qaUTDNRWr7BPBIvDd+8LpMin4Cb5j4c/A7uOY+5WxhUm3TNifueB Rohwh1NnexYQqpclcuTRA/ougLX48gQXAhUA4ub9b0v87K9LqfgLnTI/Vr0EyLs= -----END PRIVATE KEY----- cryptacular-1.2.5/src/test/resources/keys/dsa-pkcs8-priv.der000066400000000000000000000005651422604312300240550ustar00rootroot000000000000000q0 *H 0 і/P&*!aM@qwִ}qO gkKׅFSGSb.:eVy mAE ÿYsLhMPLϏ:@k93zRz8GY#=J!hąeyCknGxjFG ,={=fDpZ=LJg "u) &W0zq5q_l{${RAkvoQ>7ќ@pZW]>l5P1]j˖zؓs^%܂ZBcryptacular-1.2.5/src/test/resources/keys/dsa-pkcs8-v2-des3.pem000066400000000000000000000011671422604312300242660ustar00rootroot00000000000000-----BEGIN ENCRYPTED PRIVATE KEY----- MIIBljBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQIe5NvINrToPcCAggA MBQGCCqGSIb3DQMHBAiBg4mBYvzq1QSCAVDzYM/oK1flkdze+6mW0JF5f8EFRU9O 5bn94oEoum0EWz43OFEW9y8lBTuErzUUxXBZ3CXK5IT8AtiVTTUMnPzpMtnkSiWu iLR8bujoyfSEIQ4kewkZG4DFT2tUPOqE1O6kiiOzCiuCD1wRHH+tznGQb+mj4Afj GSD7jRyX9l5TWYWjQw3+w9Fiu12LHEDTXc7I5IotXOyOWJ+A6G4iLg7q4r7L4gJU RX4LiI7MX3Dqv1tyed9yN9xsC8ORIGG1h+F6F8yua+UErqGlfSxlvTYPI8W8O5Wr nv44CmAQOwZdVto5pkQ61YX7csrgaJHLcBtZdxVHEt7ua/887pLuHq4Fq9u+0usG 3OwPNJ/zJinTww8X1ZazVmYXcDGJK/d04URmUYuo8AGc2XFY3lCjMr4t45saQydK Du1telBhT7x2R8w6vi425AkD3QE8t531oc4= -----END ENCRYPTED PRIVATE KEY----- cryptacular-1.2.5/src/test/resources/keys/dsa-pub.der000066400000000000000000000006731422604312300226350ustar00rootroot0000000000000000+*H80륉aTe㮵'ArEo@U}Øߜ Tz&ՈQ|QƁt.7ezdFo>yu٫&鸘]KyQ*lb{D&x;pL@I9̪^ญVK+I9YZ6qz 8Vgކơk E VOw ȧ&?cV&3b~FpSg{%r.<6[ /p{% cU;s\*Jyzt;ޠ`-=З \߁u9[5UnKFF"|O1tm\[gT)>Iӄ0Ƶ0cryptacular-1.2.5/src/test/resources/keys/dsa-pub.pem000066400000000000000000000012161422604312300226360ustar00rootroot00000000000000-----BEGIN PUBLIC KEY----- MIIBtzCCASsGByqGSM44BAEwggEeAoGBAOulifG+AGGBVGWEjunG4661rydB7eFy RfHzbwVAVaPU0H3zFcOY35z1l6Pk4ZANVHq7hCbViJBR7XyrkYKaUcaB0nSPLgg3 vWWOmvGqhuR6tWRGbz4fyHl1urCRk9mrJum4mAJd3OlLugCyuIqozsYUtvJ5mlGe vir1zmxinKd7AhUA7fBEySYP53g7FLOlcEyuhIjvQAECgYBJ9baoGzn0zKpeteC4 jfbGVuKrFksr2eeY0AFJOeTtyFkCnVqrNnF674eN1RAOwA2tzzhWZ96G0AGux8ah mGsNRbj/qaUTDNRWr7BPBIvDd+8LpMin4Cb5j4c/A7uOY+5WxhUm3TNifueBRohw h1NnexYQqpclcuTRA/ougLX48gOBhQACgYEA6Tw2khtb1g0vcHu6JRgggWPZVTuj /HOH3FyjufsfHogWKrlKebZ6hnQ73qAcEgLLYKctPdCX6wnpXN+BsQGYdTkc0FsU NZD4VW5L5kaWRiLVfE8x55wXdMZtXKWqg1vL6aXYZw7RFe9U9Ck+/AG90knThDC+ xrX2FTDm6uC25rk= -----END PUBLIC KEY----- cryptacular-1.2.5/src/test/resources/keys/ec-openssl-prime256v1-named-nopass.der000066400000000000000000000002031422604312300275400ustar00rootroot00000000000000*H=0w e#m\V^UzYK(2:h\ YtCi *H=DB PtA8Lp]7!_gfz^JIIZ9.- 2y]$cryptacular-1.2.5/src/test/resources/keys/ec-openssl-prime256v1-named-nopass.pem000066400000000000000000000004561422604312300275610ustar00rootroot00000000000000-----BEGIN EC PARAMETERS----- BggqhkjOPQMBBw== -----END EC PARAMETERS----- -----BEGIN EC PRIVATE KEY----- MHcCAQEEIKtRX2H01Z5Pu3O53fQJfctXqU/3/n6p5kzKTiQ/XSMxoAoGCCqGSM49 AwEHoUQDQgAEV0bfrxH9VzCilRisNe/yynt2n1+hc/JktcTD5PK5eHFrAk3nUb7Q QClQFWMrrfbB9mmWhKuMqym8uLDsbLtrow== -----END EC PRIVATE KEY----- cryptacular-1.2.5/src/test/resources/keys/ec-openssl-prime256v1-named-pub.pem000066400000000000000000000002621422604312300270370ustar00rootroot00000000000000-----BEGIN PUBLIC KEY----- MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEV0bfrxH9VzCilRisNe/yynt2n1+h c/JktcTD5PK5eHFrAk3nUb7QQClQFWMrrfbB9mmWhKuMqym8uLDsbLtrow== -----END PUBLIC KEY----- cryptacular-1.2.5/src/test/resources/keys/ec-openssl-secp112r1-named-nopass.der000066400000000000000000000001001422604312300273350ustar00rootroot000000000000000>NV(ODŽ'˧Q+ k;/9 ׳팦Z%6>cryptacular-1.2.5/src/test/resources/keys/ec-openssl-secp112r1-named-nopass.pem000066400000000000000000000003351422604312300273560ustar00rootroot00000000000000-----BEGIN EC PARAMETERS----- BgUrgQQABg== -----END EC PARAMETERS----- -----BEGIN EC PRIVATE KEY----- MD4CAQEEDk5WBCiBT8eE8yf/y6dRoAcGBSuBBAAGoSADHgAEa8bhnjsvOSDXsxED mAjM7YymrVrLJTYchIM+Bw== -----END EC PRIVATE KEY----- cryptacular-1.2.5/src/test/resources/keys/ec-openssl-secp112r1-named-pub.pem000066400000000000000000000001761422604312300266440ustar00rootroot00000000000000-----BEGIN PUBLIC KEY----- MDIwEAYHKoZIzj0CAQYFK4EEAAYDHgAEa8bhnjsvOSDXsxEDmAjM7YymrVrLJTYc hIM+Bw== -----END PUBLIC KEY----- cryptacular-1.2.5/src/test/resources/keys/ec-openssl-secp224k1-explicit-des.pem000066400000000000000000000007251422604312300273630ustar00rootroot00000000000000-----BEGIN EC PRIVATE KEY----- Proc-Type: 4,ENCRYPTED DEK-Info: DES-CBC,36232933C6E4A23A iFYAONnfgUQvmXFtoDsb/hKXjTEhsfW+gT2rzpp0MOS2Ygidbiu9JxwZ2anT1vbV SwTfDQ/EPQTRoGft1EY4Cb6CmUEpj02ywo+U7c/smUDRTScOvh7budcuhYoNVzQL sifvukhV25nDEWydl8DPiCnVtQYNGIBh8wj1TBsbn1ucHddc0VwaGXZeYoHCbymS jAPHE+xHOrFXwAWot2FbcO6tnV7Dqd6Tw8DA1XCux9DQFfA6jxED3l7Wd79NwuKf zzpcqV5Xvcxkud5cu3WW3T8aHicKXW/dZHDKkQtet2uBnJ4nNRZErsKtFxorqimH cvvZCECsiDUyMdS67Za2PA== -----END EC PRIVATE KEY----- cryptacular-1.2.5/src/test/resources/keys/ec-openssl-secp224k1-explicit-nopass.der000066400000000000000000000003721422604312300301020ustar00rootroot0000000000000007)hatL8&"2re򈅠00(*H=m09E[3M0(igpu~e\~4BYKUmaaqv<:`U5% |WԷ5Un>Q\sLcryptacular-1.2.5/src/test/resources/keys/ec-openssl-secp224k1-explicit-nopass.pem000066400000000000000000000006221422604312300301070ustar00rootroot00000000000000-----BEGIN EC PRIVATE KEY----- MIH3AgEBBBw3HL0pymjIYdndGvIRdEwFOCYipTJyZZDb8oiFoIGVMIGSAgEBMCgG ByqGSM49AQECHQD///////////////////////////////7//+VtMAYEAQAEAQUE OQShRVszTfCZ3zD8KKFppGfp5HB1qQ9+ZQ62t6Rcfgif7X+6NEKCyvvW9+MZ98Cw vVniykvbVW1hpQIdAQAAAAAAAAAAAAAAAAAB3OjS7GGEyvCpcXafsfcCAQGhPAM6 AASYYFXr2TWWJSCu9HwUmNH0yvYPmFeEox3Ut4fBntgBo+kINaoSVfTVbj6sAfeo kgWQUadcoXNMEw== -----END EC PRIVATE KEY----- cryptacular-1.2.5/src/test/resources/keys/ec-openssl-secp224k1-explicit-pub.pem000066400000000000000000000005451422604312300273760ustar00rootroot00000000000000-----BEGIN PUBLIC KEY----- MIHdMIGeBgcqhkjOPQIBMIGSAgEBMCgGByqGSM49AQECHQD///////////////// //////////////7//+VtMAYEAQAEAQUEOQShRVszTfCZ3zD8KKFppGfp5HB1qQ9+ ZQ62t6Rcfgif7X+6NEKCyvvW9+MZ98CwvVniykvbVW1hpQIdAQAAAAAAAAAAAAAA AAAB3OjS7GGEyvCpcXafsfcCAQEDOgAEmGBV69k1liUgrvR8FJjR9Mr2D5hXhKMd 1LeHwZ7YAaPpCDWqElX01W4+rAH3qJIFkFGnXKFzTBM= -----END PUBLIC KEY----- cryptacular-1.2.5/src/test/resources/keys/ec-openssl-secp256k1-explicit-nopass.pem000066400000000000000000000003371422604312300301170ustar00rootroot00000000000000-----BEGIN EC PRIVATE KEY----- MHQCAQEEIIS3dzDcULU/YxSdkYjQnnnJMTFW3xUQb9rTjVuD6KzHoAcGBSuBBAAK oUQDQgAExo65hLAAfoKDrGFzflBulms4hLyntjaUdaoJTnBRt7P3E/d1xtERSUm3 GTWrelNA9tSw/OPq4jcPz70u4VJtAw== -----END EC PRIVATE KEY----- cryptacular-1.2.5/src/test/resources/keys/ec-openssl-secp256k1-explicit-pub.pem000066400000000000000000000002561422604312300274020ustar00rootroot00000000000000-----BEGIN PUBLIC KEY----- MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAExo65hLAAfoKDrGFzflBulms4hLyntjaU daoJTnBRt7P3E/d1xtERSUm3GTWrelNA9tSw/OPq4jcPz70u4VJtAw== -----END PUBLIC KEY----- cryptacular-1.2.5/src/test/resources/keys/ec-openssl-sect409k1-named-nopass.pem000066400000000000000000000005671422604312300273730ustar00rootroot00000000000000-----BEGIN EC PARAMETERS----- BgUrgQQAJA== -----END EC PARAMETERS----- -----BEGIN EC PRIVATE KEY----- MIGvAgEBBDNhfrS2YEmpljk4skviH8iSWr7fKoy7Dpe33DqVtjr8KoX05dYrIaSq PXpcXzAylaqsCiSgBwYFK4EEACShbANqAAQBen76TxFvShf5SFOx5KtdhrLbkB9Y DS4cEUUld3jrQCkJBY7clKBKSsLob/S4CA5j/+mWABIK2M216wcUz9NVk3HLSnd0 b02d/XAMt9E8V5vcKmVyjo5HQ0LKXnOzZs0h3SIKz9vhWQ== -----END EC PRIVATE KEY----- cryptacular-1.2.5/src/test/resources/keys/ec-openssl-sect409k1-named-pub.pem000066400000000000000000000003431422604312300266460ustar00rootroot00000000000000-----BEGIN PUBLIC KEY----- MH4wEAYHKoZIzj0CAQYFK4EEACQDagAEAXp++k8Rb0oX+UhTseSrXYay25AfWA0u HBFFJXd460ApCQWO3JSgSkrC6G/0uAgOY//plgASCtjNtesHFM/TVZNxy0p3dG9N nf1wDLfRPFeb3Cplco6OR0NCyl5zs2bNId0iCs/b4Vk= -----END PUBLIC KEY----- cryptacular-1.2.5/src/test/resources/keys/ec-openssl-sect571r1-explicit-des.pem000066400000000000000000000016741422604312300274070ustar00rootroot00000000000000-----BEGIN EC PRIVATE KEY----- Proc-Type: 4,ENCRYPTED DEK-Info: DES-CBC,A1B708E785CED928 nxXWURBdsbW4WyN25MmBNwWUjVEegjJo/XPwACRsibhAV+diUcbwTCde3qGlvVHs Z4BZVtBPP4c7Qcqvo1jAtgA4nFETptSt3iX4JFeZ4CVpmuMDpeJ9QvSHc4xh0rtj rBWhmZfmwSIiegzUA1KV3AavK3mYsKoPaW2uqhfD/nLhZewXEwSo8Fna+7XL4w8L 0qZoj7cm3Xa6CiYit6LOckVwnztPQ2S9lVYo+OQoZu79AETzoPctUL/5XozPkC8m m3Kip6Azj3SlcZCBu4HTi3YRnnxi0xtVaB5cgUICOsnY+yIJhuTC1NwqoUn3E622 2VlBHpIe2/zA3vylMmriM2dPRkgZN75Z//qE4om8ka0Auff8IIeCisLKB3QKWgGY hDdoE/Q6r9CxtfNudyZtMGt25idBfKp+toAPyH4GWWc21IKrDBDLmcEbLXGZKKjO eU/ohpjhOY7ojunSC/TcSaHKCLwW/9PCkkOb+h3Ze+PbfKLr7nRA6Sr0X8GV8e+h 1XZwMfkHCaG/u8t3+ZoVHDvogja7IjA7rSfHrLNp/YGSqwsijYwvvaU1flt8cO7K 9qDpdRULYmBLmiAI5M6W9C768ZQ/qLhzuQ0Bmy+FwSwlt3lOx9XgNkbMCNcMAuv3 6pI54RVsbXtv3vaW+Rac1O7QQOmH5L2nBYtamZ+7k4AZOmc70QrnUyHU+JxDvWTs xhAARVngIt71kDibZZmCGHneZvonXGd1PCAPkXA2C4dudhcaGk5JpkQrGt/FtazS C4HXA0/ZVBglYz4EhiLy5WNjUbxOI9KHPkqzDvww/fQ8nzP6s4aklg== -----END EC PRIVATE KEY----- cryptacular-1.2.5/src/test/resources/keys/ec-openssl-sect571r1-explicit-nopass.der000066400000000000000000000011411422604312300301150ustar00rootroot000000000000000]Gy (jGN2 %ɥZpo-"AE36ű蛇P~&cAX٠u0q0%*H=0; *H=0  0dH~"!)q/\jˌkJY3+gVn)JZxRM9 )Urz*X:3Hka:#4V)l CWbFS/Qn#<H'[HaUsh#ݜ=Qtn/NG >3*7 N.2uCnF{^#8M=*oVqV1CL)[Wor:v?H/AN/n̥t+3ײ$VVv黴CWO2@0cryptacular-1.2.5/src/test/resources/keys/ec-openssl-sect571r1-explicit-nopass.pem000066400000000000000000000015651422604312300301360ustar00rootroot00000000000000-----BEGIN EC PRIVATE KEY----- MIICXQIBAQRHq9Hu/6ik+nkgja8ol2qgR063MpyVCiX6yaXXWnBvLZOmIslBgatF MzaOGfekjsWx6JuHUBZ+9ZKP4r0mCGP/FpZB/uFYtdmgggF1MIIBcQIBATAlBgcq hkjOPQECMBoCAgI7BgkqhkjOPQECAwMwCQIBAgIBBQIBCjBkBAEBBEgC9A5+IiHy ld4pcRe389YvXGqX/8uM7/HNa6jOSpoYrYT/q72O+lkzK+etZ1ambilK/RhaeP8S qlIOTec5usoMf/7/fylVcnoDFQAqoFj3Og4zq0hrD2EEEMU6fxMjEASBkQQDAwAd NLhWKWwWwNQNPNd1CpPR0pVfqAql9A/I23sqvb3lOVD0wNKTzdcRo1tn+xSZrmAD hhTxOUq/o7TIUNkn4ed2nI7sLRkDe/JzQtpjm23M//63PWnXjGwnpgCcu8oZgPhT OSHopoRCPkO6sIpXYpGvj0YbsqizUx0vBIXBmxbi8VFuI908GkgnrxuKwVsCSAP/ /////////////////////////////////////////////+Zhzhj/VZhzCAWbGGgj hR7H3ZyhFh3pPVF01m6Dgum7L+hORwIBAqGBlQOBkgAEAJwZpe20C5w+yTMUKjet DfROAC4ydb9Dy25G4PDKewVeoyM4EeDWAU25q5A91ipvCIe0GqeS7Va40HH3VjGg Q0yRFh+BKVuTAle0b7VyOg52P8pIGqovQd3ZEk4vmh9uH8yldBYrM3+0hpTXsqcP pdoHJFZW93bpu7T+Q9tXTzLQ9wjvQJ8dAo8wqcPN4OOX -----END EC PRIVATE KEY----- cryptacular-1.2.5/src/test/resources/keys/ec-openssl-sect571r1-explicit-pub.pem000066400000000000000000000014201422604312300274070ustar00rootroot00000000000000-----BEGIN PUBLIC KEY----- MIICFzCCAX4GByqGSM49AgEwggFxAgEBMCUGByqGSM49AQIwGgICAjsGCSqGSM49 AQIDAzAJAgECAgEFAgEKMGQEAQEESAL0Dn4iIfKV3ilxF7fz1i9capf/y4zv8c1r qM5KmhithP+rvY76WTMr561nVqZuKUr9GFp4/xKqUg5N5zm6ygx//v9/KVVyegMV ACqgWPc6DjOrSGsPYQQQxTp/EyMQBIGRBAMDAB00uFYpbBbA1A0813UKk9HSlV+o CqX0D8jbeyq9veU5UPTA0pPN1xGjW2f7FJmuYAOGFPE5Sr+jtMhQ2Sfh53acjuwt GQN78nNC2mObbcz//rc9adeMbCemAJy7yhmA+FM5IeimhEI+Q7qwildika+PRhuy qLNTHS8EhcGbFuLxUW4j3TwaSCevG4rBWwJIA/////////////////////////// ////////////////////5mHOGP9VmHMIBZsYaCOFHsfdnKEWHek9UXTWboOC6bsv 6E5HAgECA4GSAAQAnBml7bQLnD7JMxQqN60N9E4ALjJ1v0PLbkbg8Mp7BV6jIzgR 4NYBTbmrkD3WKm8Ih7Qap5LtVrjQcfdWMaBDTJEWH4EpW5MCV7RvtXI6DnY/ykga qi9B3dkSTi+aH24fzKV0Fiszf7SGlNeypw+l2gckVlb3dum7tP5D21dPMtD3CO9A nx0CjzCpw83g45c= -----END PUBLIC KEY----- cryptacular-1.2.5/src/test/resources/keys/ec-openssl-sect571r1-named-nopass.der000066400000000000000000000011411422604312300273600ustar00rootroot000000000000000]Gy (jGN2 %ɥZpo-"AE36ű蛇P~&cAX٠u0q0%*H=0; *H=0  0dH~"!)q/\jˌkJY3+gVn)JZxRM9 )Urz*X:3Hka:#4V)l CWbFS/Qn#<H'[HaUsh#ݜ=Qtn/NG >3*7 N.2uCnF{^#8M=*oVqV1CL)[Wor:v?H/AN/n̥t+3ײ$VVv黴CWO2@0cryptacular-1.2.5/src/test/resources/keys/ec-openssl-sect571r1-named-nopass.pem000066400000000000000000000007101422604312300273700ustar00rootroot00000000000000-----BEGIN EC PARAMETERS----- BgUrgQQAJw== -----END EC PARAMETERS----- -----BEGIN EC PRIVATE KEY----- MIHtAgEBBEer0e7/qKT6eSCNryiXaqBHTrcynJUKJfrJpddacG8tk6YiyUGBq0Uz No4Z96SOxbHom4dQFn71ko/ivSYIY/8WlkH+4Vi12aAHBgUrgQQAJ6GBlQOBkgAE AJwZpe20C5w+yTMUKjetDfROAC4ydb9Dy25G4PDKewVeoyM4EeDWAU25q5A91ipv CIe0GqeS7Va40HH3VjGgQ0yRFh+BKVuTAle0b7VyOg52P8pIGqovQd3ZEk4vmh9u H8yldBYrM3+0hpTXsqcPpdoHJFZW93bpu7T+Q9tXTzLQ9wjvQJ8dAo8wqcPN4OOX -----END EC PRIVATE KEY----- cryptacular-1.2.5/src/test/resources/keys/ec-pkcs8-prime256v1-named-nopass.der000066400000000000000000000002121422604312300271050ustar00rootroot0000000000000000*H=*H=m0k Q_a՞Os }WO~LN$?]#1DBWF߯W05{v_sdxqkMQ@)Pc+i)lkcryptacular-1.2.5/src/test/resources/keys/ec-pkcs8-secp224k1-explicit-nopass.der000066400000000000000000000004131422604312300274430ustar00rootroot0000000000000000*H=00(*H=m09E[3M0(igpu~e\~4BYKUmaaqva0_7)hatL8&"2re򈅡<:`U5% |WԷ5Un>Q\sLcryptacular-1.2.5/src/test/resources/keys/ec-pkcs8-secp224k1-explicit-nopass.pem000066400000000000000000000006401422604312300274540ustar00rootroot00000000000000-----BEGIN PRIVATE KEY----- MIIBBwIBADCBngYHKoZIzj0CATCBkgIBATAoBgcqhkjOPQEBAh0A//////////// ///////////////////+///lbTAGBAEABAEFBDkEoUVbM03wmd8w/CihaaRn6eRw dakPfmUOtrekXH4In+1/ujRCgsr71vfjGffAsL1Z4spL21VtYaUCHQEAAAAAAAAA AAAAAAAAAdzo0uxhhMrwqXF2n7H3AgEBBGEwXwIBAQQcNxy9KcpoyGHZ3RryEXRM BTgmIqUycmWQ2/KIhaE8AzoABJhgVevZNZYlIK70fBSY0fTK9g+YV4SjHdS3h8Ge 2AGj6Qg1qhJV9NVuPqwB96iSBZBRp1yhc0wT -----END PRIVATE KEY----- cryptacular-1.2.5/src/test/resources/keys/ec-pkcs8-secp224k1-explicit-sha1-rc4-128.der000066400000000000000000000004651422604312300300010ustar00rootroot00000000000000010 *H  0KS}|YE=\)34w1&Ex9 Ŏ{sCdٽ>i%Ed94N@=˦ߝH-10|qb$U<j-«U*:<,g437cĴu4v&hB>QixsPUӞ$*mP6z d#2mܯ=V}Y Gs`+;{[O[_Y0Pv5H5MT)cryptacular-1.2.5/src/test/resources/keys/ec-pkcs8-secp224k1-explicit-v1-sha1-rc2-64.der000066400000000000000000000004651422604312300302420ustar00rootroot00000000000000010 *H  0hZK!Nݎ|s]r e•~Z)mF}~bnu-_-v߁g`"q?UVea'=~eV+/b,A^It1щs(_A,Lsnӝ9YBu LΑ O 叿qjF*YoC[u\oj7՟s$d7IoY (٢z`d h8ᛚ_@5%q_>7seT!cryptacular-1.2.5/src/test/resources/keys/ec-pkcs8-secp224k1-explicit-v2-des3.pem000066400000000000000000000010421422604312300273310ustar00rootroot00000000000000-----BEGIN ENCRYPTED PRIVATE KEY----- MIIBVjBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQIxeg91cPvDU8CAggA MBQGCCqGSIb3DQMHBAiuY7aTDDWyWQSCARA4/DvOJkuMZ1IbSS5/pyqgbGSC+fOu 6ZuBSYQqUrawNhIDkNt4rvpOlvre6PNh3RAu43wJLVrgYcSMM5ZlJI74na3ru9zd c5iZ17/rnk2ooGNRNj0mqx+fAj3Tu4d97mRizRboWAJpsQeTC4Br4uDdx8ttZzIP zp1oVMLy9Yj3HsIwwNxGu9jbgBaHiHjIzkJ+lRqza35+9sdpQwcpz2NMUQIXw34S JjUhXLaufy91d0HSfmbo8h9a0zSHiRRmHrBUBTUkBYMbLnEkZf5fAlhT21FFafSc 1v4BzuVZfvGLisjWzOZzW199G+XrYOxNmjUkvLDRyWMJYxL74YK6m6bHnZ3U+wjm N2QeMohF0rB8wA== -----END ENCRYPTED PRIVATE KEY----- cryptacular-1.2.5/src/test/resources/keys/ec-pkcs8-sect571r1-explicit-v2-aes128.pem000066400000000000000000000020361422604312300275220ustar00rootroot00000000000000-----BEGIN ENCRYPTED PRIVATE KEY----- MIICzzBJBgkqhkiG9w0BBQ0wPDAbBgkqhkiG9w0BBQwwDgQIDONm+4mH/+cCAggA MB0GCWCGSAFlAwQBAgQQdQBCHbXJepgl9MClxApnqgSCAoAph2G4i+iZzPSWxObp 66uQ5n1tNOJE6pLdbcHinwPHVYoHwp24SAel1hjX8enNuQAJaOAJvoZo9C/2rYwN 7JL7/hH+aBwojPRasnkTTBD50VYaEQa/DtTSRS/AddJ9T2DC9zwXbCzMkHJuUbtw y0ofj/RJZaMIlL0oDtQ0IdssQzxKFdEOII44r9j3lTw3bT24rKC8gbgkqHmnmO86 R3v0nnhVAj/JZFluy1PxNnsnCTcWj4mB9aHoTBuBZRiE5Qsuoq6OKTlqNQMx0Seg dbScAf6fb0cj7Cx/b7xKgR+oLO9QhyhB4oICfmPCnhJVgYlXLi9A2MsTeON0suXi 7tGIR14HsBZ8qjW9nk/PXnAnZX7PM/GJ1Md80paPOk3ffpTPrEdB6vCxmyYn7Q2m O2jcDTDUxb4847TX5EBP2fp3eX6pvbAJ6PC+RTMwXDOCYsfDDjAYypTrJZgatzqq M+kprdhvThWr4NVddjnJrGYY0QYL5dFDGXJE5Czfxp+agZdjAyAJ9kZ9TDogJNQV UrpY04er8TGieGUwphqn4kBqngoOn2PcNluc/qbLOs0fYoIqqvJzWpqlwQKGevsO x5cmot6NWVamarV7IOHanJ59ECu4Na5KxyReLSFgFHx/HCp5PM27+5FjxAZv+ZUP C0aWqG020r00k7e1RxA9sBjf7M3UXPYpY0Ip3ec4HEhvtjMjtuBtE35wBXotz8Cf 6WhTsiabQsiYcRrqZw4RZICU9v4nkJLvAyGDo0K+fI39EhtbzIJBW22QTlv03Zlj lK03vgB0ZFyLe1RjKVBjyvJzM3c3BV3cEcuEeDpu7pLQApnCK0u+YunA0pDR0n1J 40MA -----END ENCRYPTED PRIVATE KEY----- cryptacular-1.2.5/src/test/resources/keys/ec-pkcs8-sect571r1-named-v1-sha1-rc2-64.der000066400000000000000000000012351422604312300275210ustar00rootroot0000000000000000 *H 0è ?xaYTŕ[;->0.%΍X?68~r1A(?ӠE=7 %1PDD|69F/RǢ:g*Fu-vl3#,Ԏ@^Ądk 0%}M&K) yGg#ΪF NIZ< 3$3"t-'AY="D\MT:n{PEF[WnAGU_MOZZ837.)]ߧB>١e12[cPbyB$fPe0mz ( ȣx3yס*%!ww‚wY?9)BQc!WeW|7tpYSlzsŹJ#Dn D> Mkֶ݁t0hR{Ĥٱ AL$y>CĶ Q"#h>1hC~..xWߩj{uKUu$O}C [=6] TI<6fNnљun{62}cryptacular-1.2.5/src/test/resources/keys/ec-prime256v1-named-pub.der000066400000000000000000000001331422604312300253440ustar00rootroot000000000000000Y0*H=*H=BWF߯W05{v_sdxqkMQ@)Pc+i)lkcryptacular-1.2.5/src/test/resources/keys/ec-prime256v1-named-pub.pem000066400000000000000000000002621422604312300253560ustar00rootroot00000000000000-----BEGIN PUBLIC KEY----- MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEV0bfrxH9VzCilRisNe/yynt2n1+h c/JktcTD5PK5eHFrAk3nUb7QQClQFWMrrfbB9mmWhKuMqym8uLDsbLtrow== -----END PUBLIC KEY----- cryptacular-1.2.5/src/test/resources/keys/ec-secp224k1-explicit-pub.der000066400000000000000000000003401422604312300256770ustar00rootroot0000000000000000*H=00(*H=m09E[3M0(igpu~e\~4BYKUmaaqv:`U5% |WԷ5Un>Q\sLcryptacular-1.2.5/src/test/resources/keys/ec-secp224k1-explicit-pub.pem000066400000000000000000000005451422604312300257150ustar00rootroot00000000000000-----BEGIN PUBLIC KEY----- MIHdMIGeBgcqhkjOPQIBMIGSAgEBMCgGByqGSM49AQECHQD///////////////// //////////////7//+VtMAYEAQAEAQUEOQShRVszTfCZ3zD8KKFppGfp5HB1qQ9+ ZQ62t6Rcfgif7X+6NEKCyvvW9+MZ98CwvVniykvbVW1hpQIdAQAAAAAAAAAAAAAA AAAB3OjS7GGEyvCpcXafsfcCAQEDOgAEmGBV69k1liUgrvR8FJjR9Mr2D5hXhKMd 1LeHwZ7YAaPpCDWqElX01W4+rAH3qJIFkFGnXKFzTBM= -----END PUBLIC KEY----- cryptacular-1.2.5/src/test/resources/keys/rsa-openssl-des-noheader.pem000066400000000000000000000016001422604312300261020ustar00rootroot00000000000000Proc-Type: 4,ENCRYPTED DEK-Info: DES-CBC,C65E6ED4FD6921EF w9CNDiUxGP8ve2L/4M0vvfIwvwXmEfAYdVt2jFv5waqeZjrwq0eG8Xup1kSAHgaX NOX/J3GVH0F8rlMdFDdOIT3+DgDFr5hV1Pcy8e5aI+8tP0VICXGeh8tPttFj5m7k RupYtbDF6e71odLwe+9JvoWknUQYl/t7nQx/1GTa7ZKPdTKWq9r8HUJCCzAaG7xQ e44C+G1r3C9TVoI/QpPUwWgiDs9scjQRnli83OTBQKHXzUceIKY2EdpukZdIlxUa hRRXKCu+ZOxys4FDJzWgd/FEP9V6asIdVn07rDtIZX011hJLNmYaxw6/zls+gwSp Q8zRs/lohWnEKELDOJXG6dfWzWsE4/kYZsD5Z/6+w5uOIMCynd+IhG+HLb1Cyu2M gIi2o3EuWj7+RMcctNe55xs/Vm9sSlO+5cdXsfDEPrwwF69Gd4ArHRjTojQj+X0h vXzKdgjEPsEqgaa/Ln0h7MT6R9dh2feHmDEFRb1eyA4v/79IhbGypdy639SdiRAI //FpDrrZm+zlpoVtOpd6vj2YcPSIsMCHQ5osw7hlwt57o3pEyzqlR1O2zHGzngWk 09PzcVPm94Tza0pXxChJpk3Sn0cxpGgTpzLcjSOIj7ZWHZ/4kXGy5njs1/lHAMcY mioZOKuIVNZVC92bbp/uiNQP4NoaGVTGyX0qwFo81+Nb6Z0xdYsNHjp1gW0lD7m/ hhlMQT83WgApkEUcMhf9jjuN3EYQI8D07r2TbhJZ9Rc5DDlwFq04jkTrEMgDhULK JzkncgTsrpWKC0bi4MB6ky7/gcUBTsPr7/zF2czstru8LSqc3Q61lg== cryptacular-1.2.5/src/test/resources/keys/rsa-openssl-des.pem000066400000000000000000000016761422604312300243340ustar00rootroot00000000000000-----BEGIN RSA PRIVATE KEY----- Proc-Type: 4,ENCRYPTED DEK-Info: DES-CBC,C65E6ED4FD6921EF w9CNDiUxGP8ve2L/4M0vvfIwvwXmEfAYdVt2jFv5waqeZjrwq0eG8Xup1kSAHgaX NOX/J3GVH0F8rlMdFDdOIT3+DgDFr5hV1Pcy8e5aI+8tP0VICXGeh8tPttFj5m7k RupYtbDF6e71odLwe+9JvoWknUQYl/t7nQx/1GTa7ZKPdTKWq9r8HUJCCzAaG7xQ e44C+G1r3C9TVoI/QpPUwWgiDs9scjQRnli83OTBQKHXzUceIKY2EdpukZdIlxUa hRRXKCu+ZOxys4FDJzWgd/FEP9V6asIdVn07rDtIZX011hJLNmYaxw6/zls+gwSp Q8zRs/lohWnEKELDOJXG6dfWzWsE4/kYZsD5Z/6+w5uOIMCynd+IhG+HLb1Cyu2M gIi2o3EuWj7+RMcctNe55xs/Vm9sSlO+5cdXsfDEPrwwF69Gd4ArHRjTojQj+X0h vXzKdgjEPsEqgaa/Ln0h7MT6R9dh2feHmDEFRb1eyA4v/79IhbGypdy639SdiRAI //FpDrrZm+zlpoVtOpd6vj2YcPSIsMCHQ5osw7hlwt57o3pEyzqlR1O2zHGzngWk 09PzcVPm94Tza0pXxChJpk3Sn0cxpGgTpzLcjSOIj7ZWHZ/4kXGy5njs1/lHAMcY mioZOKuIVNZVC92bbp/uiNQP4NoaGVTGyX0qwFo81+Nb6Z0xdYsNHjp1gW0lD7m/ hhlMQT83WgApkEUcMhf9jjuN3EYQI8D07r2TbhJZ9Rc5DDlwFq04jkTrEMgDhULK JzkncgTsrpWKC0bi4MB6ky7/gcUBTsPr7/zF2czstru8LSqc3Q61lg== -----END RSA PRIVATE KEY----- cryptacular-1.2.5/src/test/resources/keys/rsa-openssl-des3.pem000066400000000000000000000033171422604312300244110ustar00rootroot00000000000000-----BEGIN RSA PRIVATE KEY----- Proc-Type: 4,ENCRYPTED DEK-Info: DES-EDE3-CBC,030694C414709D5A 9RGwZOuXp57EMb+PNOH80HX3iprxbFkKH6y1wIddC1VmyohyVY3JMY2sCy0RfU+Z /LSahlmq5fwmP9LdFvnxa9jj0A/9fbytUvg6AN3cHHalgFDEKXs/vXAu3katirNa t0wVqWKPARJSHHpNy7Zd2XyUN8i+dyWxRU/K/324K9fcRr51oiiEpl2H3DDlBqJE VY1a/odRUKm1YGrsN1KvZw91iCv2QfeziqCw/HQ/ehAiEqXXGpxi2zw2tPCuJM1S Qi7VAPXmyORInm0YWS0kLkNMUKjJW8uka9Mv7Fz23pQvTipHIul9XTEZWe46tMTv ueWdkqWBpmgP9is9NOEdZx+iJigJjgSeNApZjLF9HKkf9/45lcbGQS/FtUXnp1Qf MMT8V+CR5wH87kLOAJEkkpQkYKWOw52xlI+WQZrtZe7GsVo6uXRS+Yp1xyGHYYok AbTh0z+JSuViDXE80G0zn2hMaAcC/zk4UXcmCbXNDhv4uIcT6pE6n/HCbzbMUVYF rOhT/XhA4wZGeGp26J4COqsJHPTBgHbsmKrONwCogm3yCx5BndRlE+tKykBqUFke /AliECal85HfoW+VL5ojukB7C+Wy62ioG2qYepfEXKJI+j14GkQrd4bbn7huj14S 5FdXxjoWe8Ld6ZOJO8QKF8vMpnNp87hWaXXRYrfvKyEBfvUcnU3f8OBVdsDy3LX8 HPyCGNWBsuRdhxsuFVSgxP1COQ6FdOGYvZx36JXC+nRFxSd1n9BxZf5qqEdTAH2w nQiwJVbVtw/8d+vqpaavWn9/v9c+9sTrYUwoajBBOoEWiSOId+JHkdOnuAgE2OvL DtlzeB64VK6e4AU+6OSZzufZW1XiCRjYqEB+W0s8hYj5EB+W9hRIaEfA1NMMfsyG irCsIZYQD7lP+yGUICcvk2eNiU4ZwcViBq1Rv8JLimFn1X+6je2dcRmtmAby+OWA cx3WpnZ04mbI9AnrILa7qnrE7GqLtOpFDwtsQ5kc0//7zadPCg34kf96WEVHNCfW EZ0FKno0PtYbxh8bU0YnUpi3IczpbCW1e2BjvIskR80MQaz2ZSEkbsV0+uNBzOia 8Cjmo1JrdpfeE5NSiEZo5p7QqOEP3t3kL2I0mAZ8qhhN/NUTuAQAP6Lu1bncRyUT MXiHhdeOJ6LvWZ0+YehlG5sOpOfVgRKeyGI8HjTVFaff9RdTuYPEZAlDkxgwsHuF 3isenNHhH3LMRzlcjTzy19q2DUxIOxq1Nm8fkf5448fD9bNlXHmVuLBUe8m2JfAv JcP9a0PnCGPuvcSyQqKbtXkydk+4MJrB/55gEb/uClkttrCJXUKI6LvrqAH9+CNI Jn9YZ3G/ApcTsA3h/kQNoZcIPUli/bRr6wIBs1Q3VBoUEJK1f27K2LlmqsdWVqwu gMBJwIGtUmp32nVAjy+Tkb2Xexe6V7r8Rd1oiy/ewlpU6xTo68UpATeb8PmsCk3d DNpqA/ykaWz90UsSxfhadxocRxNKjZQhJC/xkDmG1x7EUGzPR3ESrMsTsP+WGLWl vORgbbVMakP6bomJLAREkfVmtQnLtSuR4ZaU8HkBKiX0Rw10n7TROQ== -----END RSA PRIVATE KEY----- cryptacular-1.2.5/src/test/resources/keys/rsa-openssl-nopass.der000066400000000000000000000011401422604312300250370ustar00rootroot000000000000000\a]Mdw'dl4T;tvWp4I? &,mi 64j;T L}f})g/]*&f&x,G!Yw2uUЉla1q,3u债?sPtGRgj9<9GӧWv10ܺg8 Ȗpio*"4P ~ssz2M՟-YLO2h10G0 MbA@@,E9A`нՃ Rq`$Y삲w_?$,0-xv˗:ލQugA澂‘mo O V;)eN,D= #PkG+L:62O@wM>sB4۬5|rSr t`~ <,<&? [HզL(AA5,H}}C'ai/qt /esB4۬5|rSr t`~ <,<&? [HզL(AA5,H}}C'ai/qt /e;z%Te&2oDT*cZ/R|+uiÑ *bH|Wզ$V&~,I $;,:fi +RW 5bkd^+#泶WN}R=:=Up{?ސZnR İHkj$If #7K\`)_UZMcryptacular-1.2.5/src/test/resources/keys/rsa-pkcs8-v1-md5-des.pem000066400000000000000000000017411422604312300247010ustar00rootroot00000000000000-----BEGIN ENCRYPTED PRIVATE KEY----- MIICoTAbBgkqhkiG9w0BBQMwDgQIGhFw3dgb3b8CAggABIICgO7i7wykRw78u/Nx swPSeJqV4Gvw38t4jGQr5arL8+z5T85URGRI102+pGBf7NtJP6U10rf24+KZL3jb 9ZhhKDr90dTZPl5XhCFygUNTsusenoW53Tf1Nh2ZbNPB72keckG3or79qgFD5ddp ZUq9HhOXksyqZm+SV8qgewXFct+4+PQMK2/CN7qF05Uw9LraTZburh2TnlA5tdwT RbPPnj+vYBLJ6liJtGnTxVq6oS9CpGK00NgvFn4OvsW8+nGrTKCvOACvdIrxHiOk XCS5Inii58p/bo/v90eajxza+1fWlhDEi0I2+UZrxn1GpcZUKUGsjSMze8bLtUa4 AMzYKi1nds1bg4FlgLUS58B2x4qwlLcliGYg9bR2iuiHKp21Yi9jILo+Rqc38/a+ kqI1Gks0RA2ifOrATEogZr2ivK3hf2vgzgIM0UUBQJaddFStIxndOV4c3RDJX0lM 5SbjvS6HHa6SF2lfLcrV6d4G3VzMIIhiwquREmy1t1CiYM3YhiEVBnB7EgLf2Hm6 5ul/FmDqg1cdie8nToyTvDlOSC2Qeql3Zo7RW88dupedkrAOOIW739yoFS7Oo1Rd e3wh7P1GRxfvrJGZWugG1X4u44zis4iA0sxoAoCXo0qbYinb7iCr8W7JLvN9HB/G Mr+/hIuNKGVfTZqbP0Lcq978kCT/BZuH706K1enVL392lsTN3fUcdhHR+0o/Ym61 SNsdc0wC5jLJ0G8hDJ/o/iUAIvj0iN/cJQ+kJiKaQiDMLgkDtDlgi4x8WaqB+ZWH oZtrQ2VcWBy4Octr9w/0qkbis3NXUJHZ3lCe5srU/4ofOCZzPx2jdJ5GvHqr8MOe mye2GBQ= -----END ENCRYPTED PRIVATE KEY----- cryptacular-1.2.5/src/test/resources/keys/rsa-pkcs8-v1-md5-rc2-64.der000066400000000000000000000012451422604312300250330ustar00rootroot0000000000000000 *H 0Kr@ ={{q ¯H0V ]b*`o㏠~V-0[lPڄJFx4Se.x0.Zp܍8 }TX>G-RGkQdJFXu1%S, gE\'uswIfu+>wp K>(}\_:nKu0CGfkk)4< q "Kw>LXU!v_@OяyA*ՋgO> !?tj0%T1e2ݒ68 BnRδ9/zJ$dV.k.I:Z;F(!qE}}P9P"<xb)$XZl?“1%=pCYPXS7#㋆e/5og/ԢwւYZGB4"Q*4G5bC=?xqH5=T( `<'c5+ֿKa2l.zYQ :7ա|C%LvUN -&$Fg#޸u$8cryptacular-1.2.5/src/test/resources/keys/rsa-pkcs8-v2-aes256-noheader.pem000066400000000000000000000017241422604312300262350ustar00rootroot00000000000000MIICzzBJBgkqhkiG9w0BBQ0wPDAbBgkqhkiG9w0BBQwwDgQICbSpN5NE6iYCAggA MB0GCWCGSAFlAwQBKgQQsTIY+PyJiePgRY0nL+SD1wSCAoCmvaOpL9cSSYtpLD/S 3Xc21VU/lu6O0FkT5fs5gxFkbnrp5ykPpdhAvlPGVAtoGDN/WnDBrYET+JCDxB12 8PsrAW5vd9sXs4YjQfdIrUDuqYllEbNo6Rp/8hvSroxT+x7RDtwAIB2eJMOjEZqN onAIHhCMf6zz+K/zXONxnCw0APgr6gBMlNn7JvElfOsCTOWjk7x3BPid7qoR4pBt EAtjsGpo6xhhc+8yQt4t1M6o8476Th/pqm1WB03LMyjPkXJXnLoP0GHXhVvLYg5y +EH9S3FLHz4SiIYM2O1uG7ji/4ByoPOE/xvuNgtNLVtNrRdgMrGQukntBbbiUZL6 qjr4Qa6EHrivXov8w5YAVrqSjfA7S7cW+qgKbpmnB+IDvClkpu24gvsqKdCThgLN HI+z9VnoBVbj+We+iKbQEytNXGiH8kls2aY5U0okii8ZWnTu1OXwyzl+vVOnQ5qU MYPmzEVPpmmArZTc1gF7udC4jwJcPnzzqFAzoc6ttQ2lX3JsZ9Ms30/WmQqEFEXj DJABY2r5Qkli+7ViGbXC9AB6+/yW1RahNe9kenSDUcZuGGlWlXc2Nv8Mx73FeYVc o24JfTiIzHlTGlOF3DAB/sOghDgXDkOd/C0+ooslih4hnfdE/0P0DGCgnuYWkk0/ 7Xz/ztRMBijn6kfm2q6EN4RDH98Tro1i+CCyh2T6LX1gC8jiJKcBcKPTuZ5Kd7U6 1coUyluOdb9wJ2sCvan/oKbJPaTVp+AdTLLtGKtg8sCeuw73AdSv2mgRryL18dOw 6oOWwXsiSQ8m+mFJgNW36BWmDIJGxej9SoO7gv+Qvqr2Ip72on82EOtgy3cUwZ9l w1oB cryptacular-1.2.5/src/test/resources/keys/rsa-pkcs8-v2-aes256.der000066400000000000000000000013231422604312300244360ustar00rootroot0000000000000000I *H  0<0 *H  0zis0 `He*T%0pl~Q 0,E[!o%-a[%q#AA$RDkn>+]-5B1)GL/IR21{H7{"su Ph%7qk W7d(v:xldc`%уxB}R-zU(r\T=wj}XidߨYژ+n?pk ZOFWQiR9e1IMHQev Р* -rê5XJ-K$znzCn*b3"//'nw@K{r ܮc{x9QI`}7ð!)^i%!-w`/rڀNBؙ3p7ud{j ;P%DV˰蠦x16=÷Tp[ encodedParamst[B[encryptedContentq~L paramsAlgtLjava/lang/String;LsealAlgq~xpur[BTxp0 !VT5uq~iG]DS}G(F}_Ng:k@6ue%mmMXaD1m[#;. NxQI:D.3g4#`ȓ!fzS0qj:ztPBEWithMD5AndTripleDEStPBEWithMD5AndTripleDESCq" oLScryptacular-1.2.5/src/test/resources/keystores/factory-bean.jceks000066400000000000000000000051001422604312300252440ustar00rootroot00000000000000rsa2048IW{sr00 +*0 Ȏr,ȏy54/2 x096]%isNgu]d6v6ghIP[u@3_lIF^Nb0lI9njDxu$̆_rKgf(r_Z</gSe > ١"8Q5Y]h)5@B[!5*՝Jaw_ET7:7NioXZص T㏣Ip,MzY44ZϣSJ%~ۏpw"PA-ĠIUF}@ -nvtJ/2`*Wyқ񢉊d,Pޅt,N|7VtHx9Op޾20!Dʹa43.%lʅ_ onForE!WS̨~Z:lD6*R 9cSb~>jouPSH!;J{)Qu^ ,h=r:a5jqٺ,Dr i A 3d9,W|}Ώ%|Rެ`"J{rZ\7kSbʵ|xS9KdIZX- ɲ뽎2 S c m?8?1{c{my6XYܔ0KA,A8 YHW+MIgkȭ y ƀT[mWd6ԭc-%qUA8 rӅ* O갴_ Rp1(cVQɤh;.9K_ 8dĻ T2Ch:V3W7uzػFw&#|7gr!"H ZjVR#1{jὧڎI>eg.u梷T2q}JBsJ̜; RvHwc`yMfɌo=0_  Rrk零KNR:˙LCBC o]Q'D}3 tz_ _X.509)0%0 %L 0  *H  0C10 &,dorg10 &,d cryptacular10 Unobody0 141028155906Z 420315155906Z0C10 &,dorg10 &,d cryptacular10 Unobody0"0  *H 0 <bV5#",{q嘀 Θ)1Gܩk:}?#Ӌ;m(H:3F ]V;¡_J/:ٷ3lsN3g5vJְ E |Myr*CϪ23SG GZ*RtH6WDH:B"x[VOz6vPUE%zLJY-:vRϓ!00U9*[u Zsoi@H0  *H  ;wA4Y; JMoLyvՕɔ|EekږI]쁍r uӆR"9|/$zȃ$ 2&1E7toabk-"T "6'Ã*7=k݋20dCu {E/9vҝ1\jQ}hr9J]Gh<8Ղ\LqI8d{AдR 3 1. GOjQ4Oaes256C5(sr3com.sun.crypto.provider.SealedObjectForKeyProtectorWY0Sxrjavax.crypto.SealedObject>6=÷Tp[ encodedParamst[B[encryptedContentq~L paramsAlgtLjava/lang/String;LsealAlgq~xpur[BTxp0 Ŝ$uq~/k&{(j/]c е.۱ C߹N *i6VMf_T diq|bAũc֍1/:˶; ivrT^%ronG+7 l'bdn1X&}o 5$Wk $pRzSrEi:@@YW$6mZ ǹMQvFl^|`|& $Tm)֍sܫXREa1Д-$d`BjXlNT. }ۋjOhkiBW\w>J L #@6qI/q5ax*oz/7_P5'|7DK t$@o)dt\7ޢ>SI).`ơT"rȾn;&n}bYO}l{aש!?Q(A <*{ ˩UTs@ZćžH:2T׈+7^MsW)Fb&Jm|Kr ׼u~Kg6+"Zcryptacular-1.2.5/src/test/resources/keystores/keystore.jceks000066400000000000000000000025421422604312300245460ustar00rootroot00000000000000mykeyC4O00 +*0 Y2 rCf Vmr7 =,(?Ɓchr!+"o\9[FqXwAY>񶐰(OskMhy=оhķkͳ)Hm&?}QJWfIIśe~z ݩbH|vfDQsB~pMHP[g"ǽ%@Q E*ȭmAc^cO=Qׄ }쑋ɖ#FE3N;Reʾ=yX9CR@+52QRhv1^u2C~ (&^(-|8TRTYe&YS< !Y}<+> _#ŃMo"X.509x0t0ݠP0  *H  0m1 0 UUS1 0 UVA10U Blacksburg10U  Virginia Tech10U  Middleware10 UMarvin0 131227160810Z 140327160810Z0m1 0 UUS1 0 UVA10U Blacksburg10U  Virginia Tech10U  Middleware10 UMarvin00  *H 0`ErZ!tcNvHncP p!M(w@j받lOڱ1gNךEuy2[FUuGW*>4] ]W5U׉QlLsb2 y誗 fK(Ko-P1J0)G(a@>V"y[:J )ɏ!k"k{^`hέ|pI6Fݹů^>&յ@Ŭ,u/_%%۶ROutO>k黳˽/D4 +k~mc^5m!00U5?BTxsr50  *H  RYa͈S#jaA6~l"$/ڎIjhpJ5Y_J-;5b~:)0*-(čCYX S}K68DrO:Y䄌J`tjNQ6L.XSO?4PݖNglcryptacular-1.2.5/src/test/resources/keystores/keystore.p12000066400000000000000000000056151422604312300240550ustar00rootroot000000000000000 0 O *H  @ <0 80 *H 00 *H 0 *H  07wi*P;RubKdY s1jC&{OTp#1Id.K)0hws==sȐ^:q?^vXfwVԞa0j5ܕyST5lsMEu9m];WˋybC.v~`~~΅k|˺@ 9,2hݔD(pijchFVnXJ(} pTA}P>4J9. KzgS.:ѢZj%20Pw$Rʇ=TwmG(ZDqBާx={U|,M~iXM-WHn-0?d Ԩb, ϖSu%~ |̔ t!-4ܲA0Oɧ(Ȼ7m0:Xf5E1R4`>*s1DV *V>ywW A*_,x2hwjAz$:V#ZhuNr 8;% ~j }7Y͓5>!)2ro[2 LM!_T?ZOޖW+ֺenyf' ?bByվ|_j$C\&bPuyclS4ͧsB}f+v~DaZ_,/eLθ&|+bkiTUCVR2}qsQDug؅@=+诿|i@z3].|}ͭĵ΃\1WgjVvJ/I(שg?HXBw.ZҌ!9_gP2 Ǭ*z^۔ !|r &"B;_YGH?H5NqRsRMhR/(Q+juHUE. V yޗCHkCsg <k#.Ȟ@> Yěs=,TGOX5(*9.굠"㌌YYr=Ѕn5EQ)1TK|q+͆3~ez@&qFM߱OB٩("˪c(,@tnjYd.v*JRX0EdBKxmA^TM!C1K&(yiA4K\Zq5t RKa  .&+f.7dS5UN DO@Kʤt̰6Ħ=xMp"НI}ݩ*_r!DkY/3!Acf#n83U лZwrM-֨$qK q Rc=Apq6@s^trdVMOBh~շjr`$xYFSY(5O &APbHw+f )% \Qw+2q%}RLx4ysȩuzخ*\|]kݷ)Ir[rHMfŅV]e7mz@[M7P'<~|vV:['5j e4Vt}<'&nXB p^.m=J4C֑,"JV/{hQF%,Vfv Ԍ0TзCMєgeŸ;!ư\|gŠ :ml)tR}2*He D!I1t+-zt@V+Xaaf!VIO0m%/ng>y+[/ׄ zaGcAۻIiZ B:(60s0tiXLR( .}P1%0# *H  1oʨI;hۀ010!0 +EFȢbe_JK{~80acryptacular-1.2.5/src/test/resources/plaintexts/000077500000000000000000000000001422604312300220205ustar00rootroot00000000000000cryptacular-1.2.5/src/test/resources/plaintexts/lorem-1190.txt000066400000000000000000000022601422604312300242670ustar00rootroot00000000000000Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean nunc leo, adipiscing et ultrices a, fermentum eget quam. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum mattis, risus tempus ultricies luctus, nisi elit consectetur velit, lacinia fringilla urna lectus sit amet nunc. Nunc nec dictum arcu. Duis id aliquet nulla. In ut augue elit. Phasellus semper ut lacus ac sagittis. Nunc elementum, dui nec ornare bibendum, ligula ante vulputate nisi, in imperdiet lectus eros rhoncus augue. Maecenas non interdum metus, vitae tempor mi. Sed rutrum, lorem quis varius tincidunt, augue elit accumsan nisl, sit amet gravida odio massa ultrices urna. Morbi suscipit mauris nec eros iaculis, vel tempus mauris bibendum. Phasellus tempor enim eget commodo gravida. Sed et risus quis orci eleifend ullamcorper. Ut et nisi et sem convallis sodales. Proin nec nibh non metus condimentum vehicula. Maecenas ut felis tellus. Cras id diam diam. Nam eu ultricies nunc, in fermentum tellus. Donec et libero a augue fermentum congue. Nulla vitae augue arcu. Donec mollis faucibus est, ac consectetur lectus aliquet at. Class aptent taciti sociosqu ad litora torquent per conubia nostcryptacular-1.2.5/src/test/resources/plaintexts/lorem-1190.txt.b64000066400000000000000000000031311422604312300246570ustar00rootroot00000000000000TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyIGFkaXBpc2Np bmcgZWxpdC4gQWVuZWFuIG51bmMgbGVvLCBhZGlwaXNjaW5nIGV0IHVsdHJpY2Vz IGEsIGZlcm1lbnR1bSBlZ2V0IApxdWFtLiBMb3JlbSBpcHN1bSBkb2xvciBzaXQg YW1ldCwgY29uc2VjdGV0dXIgYWRpcGlzY2luZyBlbGl0LiBWZXN0aWJ1bHVtIG1h dHRpcywgcmlzdXMgdGVtcHVzIHVsdHJpY2llcyBsdWN0dXMsIG5pc2kgCmVsaXQg Y29uc2VjdGV0dXIgdmVsaXQsIGxhY2luaWEgZnJpbmdpbGxhIHVybmEgbGVjdHVz IHNpdCBhbWV0IG51bmMuIE51bmMgbmVjIGRpY3R1bSBhcmN1LiBEdWlzIGlkIGFs aXF1ZXQgbnVsbGEuIEluIHV0IAphdWd1ZSBlbGl0LiBQaGFzZWxsdXMgc2VtcGVy IHV0IGxhY3VzIGFjIHNhZ2l0dGlzLiBOdW5jIGVsZW1lbnR1bSwgZHVpIG5lYyBv cm5hcmUgYmliZW5kdW0sIGxpZ3VsYSBhbnRlIHZ1bHB1dGF0ZSBuaXNpLCAKaW4g aW1wZXJkaWV0IGxlY3R1cyBlcm9zIHJob25jdXMgYXVndWUuIE1hZWNlbmFzIG5v biBpbnRlcmR1bSBtZXR1cywgdml0YWUgdGVtcG9yIG1pLgoKU2VkIHJ1dHJ1bSwg bG9yZW0gcXVpcyB2YXJpdXMgdGluY2lkdW50LCBhdWd1ZSBlbGl0IGFjY3Vtc2Fu IG5pc2wsIHNpdCBhbWV0IGdyYXZpZGEgb2RpbyBtYXNzYSB1bHRyaWNlcyB1cm5h LiBNb3JiaSAKc3VzY2lwaXQgbWF1cmlzIG5lYyBlcm9zIGlhY3VsaXMsIHZlbCB0 ZW1wdXMgbWF1cmlzIGJpYmVuZHVtLiBQaGFzZWxsdXMgdGVtcG9yIGVuaW0gZWdl dCBjb21tb2RvIGdyYXZpZGEuIFNlZCBldCByaXN1cyAKcXVpcyBvcmNpIGVsZWlm ZW5kIHVsbGFtY29ycGVyLiBVdCBldCBuaXNpIGV0IHNlbSBjb252YWxsaXMgc29k YWxlcy4gUHJvaW4gbmVjIG5pYmggbm9uIG1ldHVzIGNvbmRpbWVudHVtIHZlaGlj dWxhLiAKTWFlY2VuYXMgdXQgZmVsaXMgdGVsbHVzLiBDcmFzIGlkIGRpYW0gZGlh bS4gTmFtIGV1IHVsdHJpY2llcyBudW5jLCBpbiBmZXJtZW50dW0gdGVsbHVzLiBE b25lYyBldCBsaWJlcm8gYSBhdWd1ZSAKZmVybWVudHVtIGNvbmd1ZS4gTnVsbGEg dml0YWUgYXVndWUgYXJjdS4gRG9uZWMgbW9sbGlzIGZhdWNpYnVzIGVzdCwgYWMg Y29uc2VjdGV0dXIgbGVjdHVzIGFsaXF1ZXQgYXQuIENsYXNzIGFwdGVudCAKdGFj aXRpIHNvY2lvc3F1IGFkIGxpdG9yYSB0b3JxdWVudCBwZXIgY29udWJpYSBub3N0 cryptacular-1.2.5/src/test/resources/plaintexts/lorem-1190.txt.b64.crlf000066400000000000000000000031621422604312300256100ustar00rootroot00000000000000TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyIGFkaXBpc2Np bmcgZWxpdC4gQWVuZWFuIG51bmMgbGVvLCBhZGlwaXNjaW5nIGV0IHVsdHJpY2Vz IGEsIGZlcm1lbnR1bSBlZ2V0IApxdWFtLiBMb3JlbSBpcHN1bSBkb2xvciBzaXQg YW1ldCwgY29uc2VjdGV0dXIgYWRpcGlzY2luZyBlbGl0LiBWZXN0aWJ1bHVtIG1h dHRpcywgcmlzdXMgdGVtcHVzIHVsdHJpY2llcyBsdWN0dXMsIG5pc2kgCmVsaXQg Y29uc2VjdGV0dXIgdmVsaXQsIGxhY2luaWEgZnJpbmdpbGxhIHVybmEgbGVjdHVz IHNpdCBhbWV0IG51bmMuIE51bmMgbmVjIGRpY3R1bSBhcmN1LiBEdWlzIGlkIGFs aXF1ZXQgbnVsbGEuIEluIHV0IAphdWd1ZSBlbGl0LiBQaGFzZWxsdXMgc2VtcGVy IHV0IGxhY3VzIGFjIHNhZ2l0dGlzLiBOdW5jIGVsZW1lbnR1bSwgZHVpIG5lYyBv cm5hcmUgYmliZW5kdW0sIGxpZ3VsYSBhbnRlIHZ1bHB1dGF0ZSBuaXNpLCAKaW4g aW1wZXJkaWV0IGxlY3R1cyBlcm9zIHJob25jdXMgYXVndWUuIE1hZWNlbmFzIG5v biBpbnRlcmR1bSBtZXR1cywgdml0YWUgdGVtcG9yIG1pLgoKU2VkIHJ1dHJ1bSwg bG9yZW0gcXVpcyB2YXJpdXMgdGluY2lkdW50LCBhdWd1ZSBlbGl0IGFjY3Vtc2Fu IG5pc2wsIHNpdCBhbWV0IGdyYXZpZGEgb2RpbyBtYXNzYSB1bHRyaWNlcyB1cm5h LiBNb3JiaSAKc3VzY2lwaXQgbWF1cmlzIG5lYyBlcm9zIGlhY3VsaXMsIHZlbCB0 ZW1wdXMgbWF1cmlzIGJpYmVuZHVtLiBQaGFzZWxsdXMgdGVtcG9yIGVuaW0gZWdl dCBjb21tb2RvIGdyYXZpZGEuIFNlZCBldCByaXN1cyAKcXVpcyBvcmNpIGVsZWlm ZW5kIHVsbGFtY29ycGVyLiBVdCBldCBuaXNpIGV0IHNlbSBjb252YWxsaXMgc29k YWxlcy4gUHJvaW4gbmVjIG5pYmggbm9uIG1ldHVzIGNvbmRpbWVudHVtIHZlaGlj dWxhLiAKTWFlY2VuYXMgdXQgZmVsaXMgdGVsbHVzLiBDcmFzIGlkIGRpYW0gZGlh bS4gTmFtIGV1IHVsdHJpY2llcyBudW5jLCBpbiBmZXJtZW50dW0gdGVsbHVzLiBE b25lYyBldCBsaWJlcm8gYSBhdWd1ZSAKZmVybWVudHVtIGNvbmd1ZS4gTnVsbGEg dml0YWUgYXVndWUgYXJjdS4gRG9uZWMgbW9sbGlzIGZhdWNpYnVzIGVzdCwgYWMg Y29uc2VjdGV0dXIgbGVjdHVzIGFsaXF1ZXQgYXQuIENsYXNzIGFwdGVudCAKdGFj aXRpIHNvY2lvc3F1IGFkIGxpdG9yYSB0b3JxdWVudCBwZXIgY29udWJpYSBub3N0 cryptacular-1.2.5/src/test/resources/plaintexts/lorem-1200.txt000066400000000000000000000022731422604312300242630ustar00rootroot00000000000000Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean nunc leo, adipiscing et ultrices a, fermentum eget quam. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum mattis, risus tempus ultricies luctus, nisi elit consectetur velit, lacinia fringilla urna lectus sit amet nunc. Nunc nec dictum arcu. Duis id aliquet nulla. In ut augue elit. Phasellus semper ut lacus ac sagittis. Nunc elementum, dui nec ornare bibendum, ligula ante vulputate nisi, in imperdiet lectus eros rhoncus augue. Maecenas non interdum metus, vitae tempor mi. Sed rutrum, lorem quis varius tincidunt, augue elit accumsan nisl, sit amet gravida odio massa ultrices urna. Morbi suscipit mauris nec eros iaculis, vel tempus mauris bibendum. Phasellus tempor enim eget commodo gravida. Sed et risus quis orci eleifend ullamcorper. Ut et nisi et sem convallis sodales. Proin nec nibh non metus condimentum vehicula. Maecenas ut felis tellus. Cras id diam diam. Nam eu ultricies nunc, in fermentum tellus. Donec et libero a augue fermentum congue. Nulla vitae augue arcu. Donec mollis faucibus est, ac consectetur lectus aliquet at. Class aptent taciti sociosqu ad litora torquent per conubia nostra posuere.cryptacular-1.2.5/src/test/resources/plaintexts/lorem-1200.txt.b64000066400000000000000000000031521422604312300246520ustar00rootroot00000000000000TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyIGFkaXBpc2Np bmcgZWxpdC4gQWVuZWFuIG51bmMgbGVvLCBhZGlwaXNjaW5nIGV0IHVsdHJpY2Vz IGEsIGZlcm1lbnR1bSBlZ2V0IApxdWFtLiBMb3JlbSBpcHN1bSBkb2xvciBzaXQg YW1ldCwgY29uc2VjdGV0dXIgYWRpcGlzY2luZyBlbGl0LiBWZXN0aWJ1bHVtIG1h dHRpcywgcmlzdXMgdGVtcHVzIHVsdHJpY2llcyBsdWN0dXMsIG5pc2kgCmVsaXQg Y29uc2VjdGV0dXIgdmVsaXQsIGxhY2luaWEgZnJpbmdpbGxhIHVybmEgbGVjdHVz IHNpdCBhbWV0IG51bmMuIE51bmMgbmVjIGRpY3R1bSBhcmN1LiBEdWlzIGlkIGFs aXF1ZXQgbnVsbGEuIEluIHV0IAphdWd1ZSBlbGl0LiBQaGFzZWxsdXMgc2VtcGVy IHV0IGxhY3VzIGFjIHNhZ2l0dGlzLiBOdW5jIGVsZW1lbnR1bSwgZHVpIG5lYyBv cm5hcmUgYmliZW5kdW0sIGxpZ3VsYSBhbnRlIHZ1bHB1dGF0ZSBuaXNpLCAKaW4g aW1wZXJkaWV0IGxlY3R1cyBlcm9zIHJob25jdXMgYXVndWUuIE1hZWNlbmFzIG5v biBpbnRlcmR1bSBtZXR1cywgdml0YWUgdGVtcG9yIG1pLgoKU2VkIHJ1dHJ1bSwg bG9yZW0gcXVpcyB2YXJpdXMgdGluY2lkdW50LCBhdWd1ZSBlbGl0IGFjY3Vtc2Fu IG5pc2wsIHNpdCBhbWV0IGdyYXZpZGEgb2RpbyBtYXNzYSB1bHRyaWNlcyB1cm5h LiBNb3JiaSAKc3VzY2lwaXQgbWF1cmlzIG5lYyBlcm9zIGlhY3VsaXMsIHZlbCB0 ZW1wdXMgbWF1cmlzIGJpYmVuZHVtLiBQaGFzZWxsdXMgdGVtcG9yIGVuaW0gZWdl dCBjb21tb2RvIGdyYXZpZGEuIFNlZCBldCByaXN1cyAKcXVpcyBvcmNpIGVsZWlm ZW5kIHVsbGFtY29ycGVyLiBVdCBldCBuaXNpIGV0IHNlbSBjb252YWxsaXMgc29k YWxlcy4gUHJvaW4gbmVjIG5pYmggbm9uIG1ldHVzIGNvbmRpbWVudHVtIHZlaGlj dWxhLiAKTWFlY2VuYXMgdXQgZmVsaXMgdGVsbHVzLiBDcmFzIGlkIGRpYW0gZGlh bS4gTmFtIGV1IHVsdHJpY2llcyBudW5jLCBpbiBmZXJtZW50dW0gdGVsbHVzLiBE b25lYyBldCBsaWJlcm8gYSBhdWd1ZSAKZmVybWVudHVtIGNvbmd1ZS4gTnVsbGEg dml0YWUgYXVndWUgYXJjdS4gRG9uZWMgbW9sbGlzIGZhdWNpYnVzIGVzdCwgYWMg Y29uc2VjdGV0dXIgbGVjdHVzIGFsaXF1ZXQgYXQuIENsYXNzIGFwdGVudCAKdGFj aXRpIHNvY2lvc3F1IGFkIGxpdG9yYSB0b3JxdWVudCBwZXIgY29udWJpYSBub3N0 cmEgcG9zdWVyZS4= cryptacular-1.2.5/src/test/resources/plaintexts/lorem-1200.txt.b64.crlf000066400000000000000000000032041422604312300255750ustar00rootroot00000000000000TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyIGFkaXBpc2Np bmcgZWxpdC4gQWVuZWFuIG51bmMgbGVvLCBhZGlwaXNjaW5nIGV0IHVsdHJpY2Vz IGEsIGZlcm1lbnR1bSBlZ2V0IApxdWFtLiBMb3JlbSBpcHN1bSBkb2xvciBzaXQg YW1ldCwgY29uc2VjdGV0dXIgYWRpcGlzY2luZyBlbGl0LiBWZXN0aWJ1bHVtIG1h dHRpcywgcmlzdXMgdGVtcHVzIHVsdHJpY2llcyBsdWN0dXMsIG5pc2kgCmVsaXQg Y29uc2VjdGV0dXIgdmVsaXQsIGxhY2luaWEgZnJpbmdpbGxhIHVybmEgbGVjdHVz IHNpdCBhbWV0IG51bmMuIE51bmMgbmVjIGRpY3R1bSBhcmN1LiBEdWlzIGlkIGFs aXF1ZXQgbnVsbGEuIEluIHV0IAphdWd1ZSBlbGl0LiBQaGFzZWxsdXMgc2VtcGVy IHV0IGxhY3VzIGFjIHNhZ2l0dGlzLiBOdW5jIGVsZW1lbnR1bSwgZHVpIG5lYyBv cm5hcmUgYmliZW5kdW0sIGxpZ3VsYSBhbnRlIHZ1bHB1dGF0ZSBuaXNpLCAKaW4g aW1wZXJkaWV0IGxlY3R1cyBlcm9zIHJob25jdXMgYXVndWUuIE1hZWNlbmFzIG5v biBpbnRlcmR1bSBtZXR1cywgdml0YWUgdGVtcG9yIG1pLgoKU2VkIHJ1dHJ1bSwg bG9yZW0gcXVpcyB2YXJpdXMgdGluY2lkdW50LCBhdWd1ZSBlbGl0IGFjY3Vtc2Fu IG5pc2wsIHNpdCBhbWV0IGdyYXZpZGEgb2RpbyBtYXNzYSB1bHRyaWNlcyB1cm5h LiBNb3JiaSAKc3VzY2lwaXQgbWF1cmlzIG5lYyBlcm9zIGlhY3VsaXMsIHZlbCB0 ZW1wdXMgbWF1cmlzIGJpYmVuZHVtLiBQaGFzZWxsdXMgdGVtcG9yIGVuaW0gZWdl dCBjb21tb2RvIGdyYXZpZGEuIFNlZCBldCByaXN1cyAKcXVpcyBvcmNpIGVsZWlm ZW5kIHVsbGFtY29ycGVyLiBVdCBldCBuaXNpIGV0IHNlbSBjb252YWxsaXMgc29k YWxlcy4gUHJvaW4gbmVjIG5pYmggbm9uIG1ldHVzIGNvbmRpbWVudHVtIHZlaGlj dWxhLiAKTWFlY2VuYXMgdXQgZmVsaXMgdGVsbHVzLiBDcmFzIGlkIGRpYW0gZGlh bS4gTmFtIGV1IHVsdHJpY2llcyBudW5jLCBpbiBmZXJtZW50dW0gdGVsbHVzLiBE b25lYyBldCBsaWJlcm8gYSBhdWd1ZSAKZmVybWVudHVtIGNvbmd1ZS4gTnVsbGEg dml0YWUgYXVndWUgYXJjdS4gRG9uZWMgbW9sbGlzIGZhdWNpYnVzIGVzdCwgYWMg Y29uc2VjdGV0dXIgbGVjdHVzIGFsaXF1ZXQgYXQuIENsYXNzIGFwdGVudCAKdGFj aXRpIHNvY2lvc3F1IGFkIGxpdG9yYSB0b3JxdWVudCBwZXIgY29udWJpYSBub3N0 cmEgcG9zdWVyZS4= cryptacular-1.2.5/src/test/resources/plaintexts/lorem-5000.txt000066400000000000000000000116761422604312300242740ustar00rootroot00000000000000Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent tempus sagittis erat et facilisis. In quis eleifend dolor. Duis sagittis porttitor risus non aliquam. Etiam malesuada purus et felis feugiat, et condimentum augue sagittis. Donec posuere semper lacus eget sollicitudin. Ut feugiat diam ipsum, ut tempor turpis vehicula sed. Duis euismod euismod rhoncus. Praesent vitae leo egestas neque pellentesque ultricies tincidunt et purus. Suspendisse interdum blandit urna imperdiet euismod. Etiam et metus molestie nisl imperdiet cursus. Donec ullamcorper purus sed leo rutrum tincidunt. Pellentesque iaculis tristique pellentesque. Pellentesque cursus porta nisl, at iaculis ligula dapibus quis. Morbi mattis, eros porta blandit ullamcorper, arcu dolor fermentum nunc, ac cursus magna arcu id nulla. Quisque urna urna, dapibus et blandit vitae, placerat quis nibh. Sed ac est eget nisl ultrices gravida. Aliquam id suscipit ligula. Suspendisse sollicitudin fermentum turpis. Donec auctor consectetur purus eu bibendum. Pellentesque eget elit vitae augue bibendum lacinia. Quisque convallis tristique turpis id viverra. Mauris aliquet bibendum bibendum. Morbi volutpat id dolor non aliquam. Aliquam ultrices dapibus diam, vel porttitor magna elementum et. Fusce eu dui quis dui malesuada tempor vel rhoncus orci. Vestibulum id vestibulum augue. Aenean turpis felis, auctor vel neque eget, fermentum semper ante. Proin imperdiet quis tellus vitae pulvinar. Phasellus est metus, molestie eget diam vel, consequat hendrerit erat. Donec laoreet vitae quam eu sagittis. Vivamus quis tincidunt turpis. Integer venenatis turpis velit. Morbi tempor elit mi, ac lacinia ligula interdum vel. Donec commodo erat vitae porta tincidunt. Quisque ullamcorper, est non lacinia consequat, turpis nunc feugiat metus, quis tincidunt lectus augue et ipsum. Curabitur lobortis facilisis luctus. Sed placerat ligula enim, at dignissim urna condimentum eget. Etiam tempus facilisis nibh, lobortis tincidunt ante ultrices at. Integer sed purus nec dolor aliquet dictum ut id mi. Nulla vel sem ipsum. Aliquam nec tincidunt metus. Interdum et malesuada fames ac ante ipsum primis in faucibus. Sed suscipit ipsum a varius commodo. Vestibulum bibendum at lectus sit amet vehicula. Pellentesque ullamcorper est eu purus iaculis laoreet. Nam nec neque eget massa faucibus elementum eu quis eros. Ut id laoreet dolor. Donec eget gravida elit, ac rutrum elit. Quisque lacus neque, fringilla in turpis et, gravida volutpat orci. Integer in nisl eget lorem ullamcorper condimentum nec venenatis lorem. Curabitur eget magna eu dui fermentum fringilla sed ut dolor. Nulla vestibulum nunc et pharetra imperdiet. Morbi tristique porttitor odio, nec pharetra orci lacinia vitae. Duis vestibulum diam ullamcorper massa vestibulum, ut auctor lorem imperdiet. Vestibulum et venenatis tellus. Suspendisse convallis, odio ac dictum lacinia, neque quam tincidunt risus, non ornare dolor lacus nec tellus. Mauris rhoncus fermentum neque sit amet sollicitudin. Pellentesque nulla magna, commodo vel tincidunt sed, hendrerit quis justo. In hac habitasse platea dictumst. Nunc et est augue. Vivamus pretium, odio vel sodales semper, risus ante elementum urna, ac ullamcorper massa neque non ligula. Cras id tellus quis urna adipiscing elementum. Donec adipiscing magna vel suscipit vulputate. Quisque in mi eget orci viverra scelerisque nec et magna. Cras posuere, urna lacinia dictum rhoncus, justo orci suscipit metus, ut gravida orci nulla in turpis. Interdum et malesuada fames ac ante ipsum primis in faucibus. In volutpat feugiat turpis, non faucibus nunc interdum ut. Praesent ornare sagittis urna, id lacinia tortor suscipit et. Pellentesque tempor mi ac nisi varius, vitae ullamcorper urna suscipit. Aliquam pellentesque vulputate turpis vestibulum eleifend. Donec faucibus eu felis eu blandit. Pellentesque pulvinar, elit non lacinia porttitor, orci nibh iaculis augue, ac scelerisque mi tellus quis tortor. Interdum et malesuada fames ac ante ipsum primis in faucibus. Cras nec suscipit risus, ut ultricies elit. Suspendisse et fringilla urna. Donec luctus et nisi quis bibendum. Quisque sed augue lacinia, pellentesque diam vitae, convallis metus. Nam vehicula metus eget orci sagittis sodales. Curabitur egestas congue nibh sed luctus. Nam luctus tellus at nulla vestibulum, rutrum fermentum est vulputate. Nulla condimentum dui a dolor lobortis, eu aliquet odio pretium. Phasellus id pretium nulla. Donec eu tincidunt lectus, in ornare orci. Pellentesque mollis est eget turpis aliquet, vel tempor velit fringilla. Curabitur a leo elementum elit pellentesque tincidunt vestibulum sit amet mi. Vestibulum varius pulvinar nisi sit amet dignissim. Vestibulum dui velit, commodo vel augue non, dapibus imperdiet mi. Etiam at turpis velit. Suspendisse tempor, nisl a congue pellentesque, erat tellus gravida sapien, et sodales nulla nisi at mauris. Nunc consectetur ligula vitae posuere pharetra. Integer id suscipit sem. Praesent cras amet.cryptacular-1.2.5/src/test/resources/plaintexts/lorem-5000.txt.b64000066400000000000000000000152761422604312300246660ustar00rootroot00000000000000TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyIGFkaXBpc2Np bmcgZWxpdC4gUHJhZXNlbnQgdGVtcHVzIHNhZ2l0dGlzIGVyYXQgZXQgZmFjaWxp c2lzLiBJbiBxdWlzIGVsZWlmZW5kIApkb2xvci4gRHVpcyBzYWdpdHRpcyBwb3J0 dGl0b3IgcmlzdXMgbm9uIGFsaXF1YW0uIEV0aWFtIG1hbGVzdWFkYSBwdXJ1cyBl dCBmZWxpcyBmZXVnaWF0LCBldCBjb25kaW1lbnR1bSBhdWd1ZSAKc2FnaXR0aXMu IERvbmVjIHBvc3VlcmUgc2VtcGVyIGxhY3VzIGVnZXQgc29sbGljaXR1ZGluLiBV dCBmZXVnaWF0IGRpYW0gaXBzdW0sIHV0IHRlbXBvciB0dXJwaXMgdmVoaWN1bGEg c2VkLiBEdWlzIApldWlzbW9kIGV1aXNtb2QgcmhvbmN1cy4gUHJhZXNlbnQgdml0 YWUgbGVvIGVnZXN0YXMgbmVxdWUgcGVsbGVudGVzcXVlIHVsdHJpY2llcyB0aW5j aWR1bnQgZXQgcHVydXMuIFN1c3BlbmRpc3NlIAppbnRlcmR1bSBibGFuZGl0IHVy bmEgaW1wZXJkaWV0IGV1aXNtb2QuIEV0aWFtIGV0IG1ldHVzIG1vbGVzdGllIG5p c2wgaW1wZXJkaWV0IGN1cnN1cy4KCkRvbmVjIHVsbGFtY29ycGVyIHB1cnVzIHNl ZCBsZW8gcnV0cnVtIHRpbmNpZHVudC4gUGVsbGVudGVzcXVlIGlhY3VsaXMgdHJp c3RpcXVlIHBlbGxlbnRlc3F1ZS4gUGVsbGVudGVzcXVlIGN1cnN1cyAKcG9ydGEg bmlzbCwgYXQgaWFjdWxpcyBsaWd1bGEgZGFwaWJ1cyBxdWlzLiBNb3JiaSBtYXR0 aXMsIGVyb3MgcG9ydGEgYmxhbmRpdCB1bGxhbWNvcnBlciwgYXJjdSBkb2xvciBm ZXJtZW50dW0gbnVuYywgYWMgCmN1cnN1cyBtYWduYSBhcmN1IGlkIG51bGxhLiBR dWlzcXVlIHVybmEgdXJuYSwgZGFwaWJ1cyBldCBibGFuZGl0IHZpdGFlLCBwbGFj ZXJhdCBxdWlzIG5pYmguIFNlZCBhYyBlc3QgZWdldCBuaXNsIAp1bHRyaWNlcyBn cmF2aWRhLiBBbGlxdWFtIGlkIHN1c2NpcGl0IGxpZ3VsYS4gU3VzcGVuZGlzc2Ug c29sbGljaXR1ZGluIGZlcm1lbnR1bSB0dXJwaXMuIERvbmVjIGF1Y3RvciBjb25z ZWN0ZXR1ciBwdXJ1cyAKZXUgYmliZW5kdW0uIFBlbGxlbnRlc3F1ZSBlZ2V0IGVs aXQgdml0YWUgYXVndWUgYmliZW5kdW0gbGFjaW5pYS4gUXVpc3F1ZSBjb252YWxs aXMgdHJpc3RpcXVlIHR1cnBpcyBpZCB2aXZlcnJhLiBNYXVyaXMgCmFsaXF1ZXQg YmliZW5kdW0gYmliZW5kdW0uIE1vcmJpIHZvbHV0cGF0IGlkIGRvbG9yIG5vbiBh bGlxdWFtLgoKQWxpcXVhbSB1bHRyaWNlcyBkYXBpYnVzIGRpYW0sIHZlbCBwb3J0 dGl0b3IgbWFnbmEgZWxlbWVudHVtIGV0LiBGdXNjZSBldSBkdWkgcXVpcyBkdWkg bWFsZXN1YWRhIHRlbXBvciB2ZWwgcmhvbmN1cyAKb3JjaS4gVmVzdGlidWx1bSBp ZCB2ZXN0aWJ1bHVtIGF1Z3VlLiBBZW5lYW4gdHVycGlzIGZlbGlzLCBhdWN0b3Ig dmVsIG5lcXVlIGVnZXQsIGZlcm1lbnR1bSBzZW1wZXIgYW50ZS4gUHJvaW4gCmlt cGVyZGlldCBxdWlzIHRlbGx1cyB2aXRhZSBwdWx2aW5hci4gUGhhc2VsbHVzIGVz dCBtZXR1cywgbW9sZXN0aWUgZWdldCBkaWFtIHZlbCwgY29uc2VxdWF0IGhlbmRy ZXJpdCBlcmF0LiBEb25lYyAKbGFvcmVldCB2aXRhZSBxdWFtIGV1IHNhZ2l0dGlz LiBWaXZhbXVzIHF1aXMgdGluY2lkdW50IHR1cnBpcy4gSW50ZWdlciB2ZW5lbmF0 aXMgdHVycGlzIHZlbGl0LgoKTW9yYmkgdGVtcG9yIGVsaXQgbWksIGFjIGxhY2lu aWEgbGlndWxhIGludGVyZHVtIHZlbC4gRG9uZWMgY29tbW9kbyBlcmF0IHZpdGFl IHBvcnRhIHRpbmNpZHVudC4gUXVpc3F1ZSB1bGxhbWNvcnBlciwgCmVzdCBub24g bGFjaW5pYSBjb25zZXF1YXQsIHR1cnBpcyBudW5jIGZldWdpYXQgbWV0dXMsIHF1 aXMgdGluY2lkdW50IGxlY3R1cyBhdWd1ZSBldCBpcHN1bS4gQ3VyYWJpdHVyIGxv Ym9ydGlzIApmYWNpbGlzaXMgbHVjdHVzLiBTZWQgcGxhY2VyYXQgbGlndWxhIGVu aW0sIGF0IGRpZ25pc3NpbSB1cm5hIGNvbmRpbWVudHVtIGVnZXQuIEV0aWFtIHRl bXB1cyBmYWNpbGlzaXMgbmliaCwgbG9ib3J0aXMgCnRpbmNpZHVudCBhbnRlIHVs dHJpY2VzIGF0LiBJbnRlZ2VyIHNlZCBwdXJ1cyBuZWMgZG9sb3IgYWxpcXVldCBk aWN0dW0gdXQgaWQgbWkuIE51bGxhIHZlbCBzZW0gaXBzdW0uIEFsaXF1YW0gbmVj IAp0aW5jaWR1bnQgbWV0dXMuIEludGVyZHVtIGV0IG1hbGVzdWFkYSBmYW1lcyBh YyBhbnRlIGlwc3VtIHByaW1pcyBpbiBmYXVjaWJ1cy4gU2VkIHN1c2NpcGl0IGlw c3VtIGEgdmFyaXVzIGNvbW1vZG8uIApWZXN0aWJ1bHVtIGJpYmVuZHVtIGF0IGxl Y3R1cyBzaXQgYW1ldCB2ZWhpY3VsYS4gUGVsbGVudGVzcXVlIHVsbGFtY29ycGVy IGVzdCBldSBwdXJ1cyBpYWN1bGlzIGxhb3JlZXQuIE5hbSBuZWMgbmVxdWUgCmVn ZXQgbWFzc2EgZmF1Y2lidXMgZWxlbWVudHVtIGV1IHF1aXMgZXJvcy4KClV0IGlk IGxhb3JlZXQgZG9sb3IuIERvbmVjIGVnZXQgZ3JhdmlkYSBlbGl0LCBhYyBydXRy dW0gZWxpdC4gUXVpc3F1ZSBsYWN1cyBuZXF1ZSwgZnJpbmdpbGxhIGluIHR1cnBp cyBldCwgZ3JhdmlkYSAKdm9sdXRwYXQgb3JjaS4gSW50ZWdlciBpbiBuaXNsIGVn ZXQgbG9yZW0gdWxsYW1jb3JwZXIgY29uZGltZW50dW0gbmVjIHZlbmVuYXRpcyBs b3JlbS4gQ3VyYWJpdHVyIGVnZXQgbWFnbmEgZXUgZHVpIApmZXJtZW50dW0gZnJp bmdpbGxhIHNlZCB1dCBkb2xvci4gTnVsbGEgdmVzdGlidWx1bSBudW5jIGV0IHBo YXJldHJhIGltcGVyZGlldC4gTW9yYmkgdHJpc3RpcXVlIHBvcnR0aXRvciBvZGlv LCBuZWMgCnBoYXJldHJhIG9yY2kgbGFjaW5pYSB2aXRhZS4gRHVpcyB2ZXN0aWJ1 bHVtIGRpYW0gdWxsYW1jb3JwZXIgbWFzc2EgdmVzdGlidWx1bSwgdXQgYXVjdG9y IGxvcmVtIGltcGVyZGlldC4gVmVzdGlidWx1bSAKZXQgdmVuZW5hdGlzIHRlbGx1 cy4gU3VzcGVuZGlzc2UgY29udmFsbGlzLCBvZGlvIGFjIGRpY3R1bSBsYWNpbmlh LCBuZXF1ZSBxdWFtIHRpbmNpZHVudCByaXN1cywgbm9uIG9ybmFyZSBkb2xvciBs YWN1cyAKbmVjIHRlbGx1cy4gTWF1cmlzIHJob25jdXMgZmVybWVudHVtIG5lcXVl IHNpdCBhbWV0IHNvbGxpY2l0dWRpbi4gUGVsbGVudGVzcXVlIG51bGxhIG1hZ25h LCBjb21tb2RvIHZlbCB0aW5jaWR1bnQgc2VkLCAKaGVuZHJlcml0IHF1aXMganVz dG8uCgpJbiBoYWMgaGFiaXRhc3NlIHBsYXRlYSBkaWN0dW1zdC4gTnVuYyBldCBl c3QgYXVndWUuIFZpdmFtdXMgcHJldGl1bSwgb2RpbyB2ZWwgc29kYWxlcyBzZW1w ZXIsIHJpc3VzIGFudGUgZWxlbWVudHVtIAp1cm5hLCBhYyB1bGxhbWNvcnBlciBt YXNzYSBuZXF1ZSBub24gbGlndWxhLiBDcmFzIGlkIHRlbGx1cyBxdWlzIHVybmEg YWRpcGlzY2luZyBlbGVtZW50dW0uIERvbmVjIGFkaXBpc2NpbmcgbWFnbmEgdmVs IApzdXNjaXBpdCB2dWxwdXRhdGUuIFF1aXNxdWUgaW4gbWkgZWdldCBvcmNpIHZp dmVycmEgc2NlbGVyaXNxdWUgbmVjIGV0IG1hZ25hLiBDcmFzIHBvc3VlcmUsIHVy bmEgbGFjaW5pYSBkaWN0dW0gCnJob25jdXMsIGp1c3RvIG9yY2kgc3VzY2lwaXQg bWV0dXMsIHV0IGdyYXZpZGEgb3JjaSBudWxsYSBpbiB0dXJwaXMuIEludGVyZHVt IGV0IG1hbGVzdWFkYSBmYW1lcyBhYyBhbnRlIGlwc3VtIHByaW1pcyAKaW4gZmF1 Y2lidXMuIEluIHZvbHV0cGF0IGZldWdpYXQgdHVycGlzLCBub24gZmF1Y2lidXMg bnVuYyBpbnRlcmR1bSB1dC4gUHJhZXNlbnQgb3JuYXJlIHNhZ2l0dGlzIHVybmEs IGlkIGxhY2luaWEgCnRvcnRvciBzdXNjaXBpdCBldC4gUGVsbGVudGVzcXVlIHRl bXBvciBtaSBhYyBuaXNpIHZhcml1cywgdml0YWUgdWxsYW1jb3JwZXIgdXJuYSBz dXNjaXBpdC4KCkFsaXF1YW0gcGVsbGVudGVzcXVlIHZ1bHB1dGF0ZSB0dXJwaXMg dmVzdGlidWx1bSBlbGVpZmVuZC4gRG9uZWMgZmF1Y2lidXMgZXUgZmVsaXMgZXUg YmxhbmRpdC4gUGVsbGVudGVzcXVlIHB1bHZpbmFyLCAKZWxpdCBub24gbGFjaW5p YSBwb3J0dGl0b3IsIG9yY2kgbmliaCBpYWN1bGlzIGF1Z3VlLCBhYyBzY2VsZXJp c3F1ZSBtaSB0ZWxsdXMgcXVpcyB0b3J0b3IuIEludGVyZHVtIGV0IG1hbGVzdWFk YSBmYW1lcyAKYWMgYW50ZSBpcHN1bSBwcmltaXMgaW4gZmF1Y2lidXMuIENyYXMg bmVjIHN1c2NpcGl0IHJpc3VzLCB1dCB1bHRyaWNpZXMgZWxpdC4gU3VzcGVuZGlz c2UgZXQgZnJpbmdpbGxhIHVybmEuIERvbmVjIApsdWN0dXMgZXQgbmlzaSBxdWlz IGJpYmVuZHVtLiBRdWlzcXVlIHNlZCBhdWd1ZSBsYWNpbmlhLCBwZWxsZW50ZXNx dWUgZGlhbSB2aXRhZSwgY29udmFsbGlzIG1ldHVzLiBOYW0gdmVoaWN1bGEgbWV0 dXMgCmVnZXQgb3JjaSBzYWdpdHRpcyBzb2RhbGVzLgoKQ3VyYWJpdHVyIGVnZXN0 YXMgY29uZ3VlIG5pYmggc2VkIGx1Y3R1cy4gTmFtIGx1Y3R1cyB0ZWxsdXMgYXQg bnVsbGEgdmVzdGlidWx1bSwgcnV0cnVtIGZlcm1lbnR1bSBlc3QgdnVscHV0YXRl LiBOdWxsYSAKY29uZGltZW50dW0gZHVpIGEgZG9sb3IgbG9ib3J0aXMsIGV1IGFs aXF1ZXQgb2RpbyBwcmV0aXVtLiBQaGFzZWxsdXMgaWQgcHJldGl1bSBudWxsYS4g RG9uZWMgZXUgdGluY2lkdW50IGxlY3R1cywgaW4gCm9ybmFyZSBvcmNpLiBQZWxs ZW50ZXNxdWUgbW9sbGlzIGVzdCBlZ2V0IHR1cnBpcyBhbGlxdWV0LCB2ZWwgdGVt cG9yIHZlbGl0IGZyaW5naWxsYS4gQ3VyYWJpdHVyIGEgbGVvIGVsZW1lbnR1bSBl bGl0IApwZWxsZW50ZXNxdWUgdGluY2lkdW50IHZlc3RpYnVsdW0gc2l0IGFtZXQg bWkuIFZlc3RpYnVsdW0gdmFyaXVzIHB1bHZpbmFyIG5pc2kgc2l0IGFtZXQgZGln bmlzc2ltLiBWZXN0aWJ1bHVtIGR1aSAKdmVsaXQsIGNvbW1vZG8gdmVsIGF1Z3Vl IG5vbiwgZGFwaWJ1cyBpbXBlcmRpZXQgbWkuCgpFdGlhbSBhdCB0dXJwaXMgdmVs aXQuIFN1c3BlbmRpc3NlIHRlbXBvciwgbmlzbCBhIGNvbmd1ZSBwZWxsZW50ZXNx dWUsIGVyYXQgdGVsbHVzIGdyYXZpZGEgc2FwaWVuLCBldCBzb2RhbGVzIG51bGxh IApuaXNpIGF0IG1hdXJpcy4gTnVuYyBjb25zZWN0ZXR1ciBsaWd1bGEgdml0YWUg cG9zdWVyZSBwaGFyZXRyYS4gSW50ZWdlciBpZCBzdXNjaXBpdCBzZW0uIFByYWVz ZW50IGNyYXMgYW1ldC4= cryptacular-1.2.5/src/test/resources/plaintexts/lorem-5000.txt.b64.crlf000066400000000000000000000154501422604312300256050ustar00rootroot00000000000000TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyIGFkaXBpc2Np bmcgZWxpdC4gUHJhZXNlbnQgdGVtcHVzIHNhZ2l0dGlzIGVyYXQgZXQgZmFjaWxp c2lzLiBJbiBxdWlzIGVsZWlmZW5kIApkb2xvci4gRHVpcyBzYWdpdHRpcyBwb3J0 dGl0b3IgcmlzdXMgbm9uIGFsaXF1YW0uIEV0aWFtIG1hbGVzdWFkYSBwdXJ1cyBl dCBmZWxpcyBmZXVnaWF0LCBldCBjb25kaW1lbnR1bSBhdWd1ZSAKc2FnaXR0aXMu IERvbmVjIHBvc3VlcmUgc2VtcGVyIGxhY3VzIGVnZXQgc29sbGljaXR1ZGluLiBV dCBmZXVnaWF0IGRpYW0gaXBzdW0sIHV0IHRlbXBvciB0dXJwaXMgdmVoaWN1bGEg c2VkLiBEdWlzIApldWlzbW9kIGV1aXNtb2QgcmhvbmN1cy4gUHJhZXNlbnQgdml0 YWUgbGVvIGVnZXN0YXMgbmVxdWUgcGVsbGVudGVzcXVlIHVsdHJpY2llcyB0aW5j aWR1bnQgZXQgcHVydXMuIFN1c3BlbmRpc3NlIAppbnRlcmR1bSBibGFuZGl0IHVy bmEgaW1wZXJkaWV0IGV1aXNtb2QuIEV0aWFtIGV0IG1ldHVzIG1vbGVzdGllIG5p c2wgaW1wZXJkaWV0IGN1cnN1cy4KCkRvbmVjIHVsbGFtY29ycGVyIHB1cnVzIHNl ZCBsZW8gcnV0cnVtIHRpbmNpZHVudC4gUGVsbGVudGVzcXVlIGlhY3VsaXMgdHJp c3RpcXVlIHBlbGxlbnRlc3F1ZS4gUGVsbGVudGVzcXVlIGN1cnN1cyAKcG9ydGEg bmlzbCwgYXQgaWFjdWxpcyBsaWd1bGEgZGFwaWJ1cyBxdWlzLiBNb3JiaSBtYXR0 aXMsIGVyb3MgcG9ydGEgYmxhbmRpdCB1bGxhbWNvcnBlciwgYXJjdSBkb2xvciBm ZXJtZW50dW0gbnVuYywgYWMgCmN1cnN1cyBtYWduYSBhcmN1IGlkIG51bGxhLiBR dWlzcXVlIHVybmEgdXJuYSwgZGFwaWJ1cyBldCBibGFuZGl0IHZpdGFlLCBwbGFj ZXJhdCBxdWlzIG5pYmguIFNlZCBhYyBlc3QgZWdldCBuaXNsIAp1bHRyaWNlcyBn cmF2aWRhLiBBbGlxdWFtIGlkIHN1c2NpcGl0IGxpZ3VsYS4gU3VzcGVuZGlzc2Ug c29sbGljaXR1ZGluIGZlcm1lbnR1bSB0dXJwaXMuIERvbmVjIGF1Y3RvciBjb25z ZWN0ZXR1ciBwdXJ1cyAKZXUgYmliZW5kdW0uIFBlbGxlbnRlc3F1ZSBlZ2V0IGVs aXQgdml0YWUgYXVndWUgYmliZW5kdW0gbGFjaW5pYS4gUXVpc3F1ZSBjb252YWxs aXMgdHJpc3RpcXVlIHR1cnBpcyBpZCB2aXZlcnJhLiBNYXVyaXMgCmFsaXF1ZXQg YmliZW5kdW0gYmliZW5kdW0uIE1vcmJpIHZvbHV0cGF0IGlkIGRvbG9yIG5vbiBh bGlxdWFtLgoKQWxpcXVhbSB1bHRyaWNlcyBkYXBpYnVzIGRpYW0sIHZlbCBwb3J0 dGl0b3IgbWFnbmEgZWxlbWVudHVtIGV0LiBGdXNjZSBldSBkdWkgcXVpcyBkdWkg bWFsZXN1YWRhIHRlbXBvciB2ZWwgcmhvbmN1cyAKb3JjaS4gVmVzdGlidWx1bSBp ZCB2ZXN0aWJ1bHVtIGF1Z3VlLiBBZW5lYW4gdHVycGlzIGZlbGlzLCBhdWN0b3Ig dmVsIG5lcXVlIGVnZXQsIGZlcm1lbnR1bSBzZW1wZXIgYW50ZS4gUHJvaW4gCmlt cGVyZGlldCBxdWlzIHRlbGx1cyB2aXRhZSBwdWx2aW5hci4gUGhhc2VsbHVzIGVz dCBtZXR1cywgbW9sZXN0aWUgZWdldCBkaWFtIHZlbCwgY29uc2VxdWF0IGhlbmRy ZXJpdCBlcmF0LiBEb25lYyAKbGFvcmVldCB2aXRhZSBxdWFtIGV1IHNhZ2l0dGlz LiBWaXZhbXVzIHF1aXMgdGluY2lkdW50IHR1cnBpcy4gSW50ZWdlciB2ZW5lbmF0 aXMgdHVycGlzIHZlbGl0LgoKTW9yYmkgdGVtcG9yIGVsaXQgbWksIGFjIGxhY2lu aWEgbGlndWxhIGludGVyZHVtIHZlbC4gRG9uZWMgY29tbW9kbyBlcmF0IHZpdGFl IHBvcnRhIHRpbmNpZHVudC4gUXVpc3F1ZSB1bGxhbWNvcnBlciwgCmVzdCBub24g bGFjaW5pYSBjb25zZXF1YXQsIHR1cnBpcyBudW5jIGZldWdpYXQgbWV0dXMsIHF1 aXMgdGluY2lkdW50IGxlY3R1cyBhdWd1ZSBldCBpcHN1bS4gQ3VyYWJpdHVyIGxv Ym9ydGlzIApmYWNpbGlzaXMgbHVjdHVzLiBTZWQgcGxhY2VyYXQgbGlndWxhIGVu aW0sIGF0IGRpZ25pc3NpbSB1cm5hIGNvbmRpbWVudHVtIGVnZXQuIEV0aWFtIHRl bXB1cyBmYWNpbGlzaXMgbmliaCwgbG9ib3J0aXMgCnRpbmNpZHVudCBhbnRlIHVs dHJpY2VzIGF0LiBJbnRlZ2VyIHNlZCBwdXJ1cyBuZWMgZG9sb3IgYWxpcXVldCBk aWN0dW0gdXQgaWQgbWkuIE51bGxhIHZlbCBzZW0gaXBzdW0uIEFsaXF1YW0gbmVj IAp0aW5jaWR1bnQgbWV0dXMuIEludGVyZHVtIGV0IG1hbGVzdWFkYSBmYW1lcyBh YyBhbnRlIGlwc3VtIHByaW1pcyBpbiBmYXVjaWJ1cy4gU2VkIHN1c2NpcGl0IGlw c3VtIGEgdmFyaXVzIGNvbW1vZG8uIApWZXN0aWJ1bHVtIGJpYmVuZHVtIGF0IGxl Y3R1cyBzaXQgYW1ldCB2ZWhpY3VsYS4gUGVsbGVudGVzcXVlIHVsbGFtY29ycGVy IGVzdCBldSBwdXJ1cyBpYWN1bGlzIGxhb3JlZXQuIE5hbSBuZWMgbmVxdWUgCmVn ZXQgbWFzc2EgZmF1Y2lidXMgZWxlbWVudHVtIGV1IHF1aXMgZXJvcy4KClV0IGlk IGxhb3JlZXQgZG9sb3IuIERvbmVjIGVnZXQgZ3JhdmlkYSBlbGl0LCBhYyBydXRy dW0gZWxpdC4gUXVpc3F1ZSBsYWN1cyBuZXF1ZSwgZnJpbmdpbGxhIGluIHR1cnBp cyBldCwgZ3JhdmlkYSAKdm9sdXRwYXQgb3JjaS4gSW50ZWdlciBpbiBuaXNsIGVn ZXQgbG9yZW0gdWxsYW1jb3JwZXIgY29uZGltZW50dW0gbmVjIHZlbmVuYXRpcyBs b3JlbS4gQ3VyYWJpdHVyIGVnZXQgbWFnbmEgZXUgZHVpIApmZXJtZW50dW0gZnJp bmdpbGxhIHNlZCB1dCBkb2xvci4gTnVsbGEgdmVzdGlidWx1bSBudW5jIGV0IHBo YXJldHJhIGltcGVyZGlldC4gTW9yYmkgdHJpc3RpcXVlIHBvcnR0aXRvciBvZGlv LCBuZWMgCnBoYXJldHJhIG9yY2kgbGFjaW5pYSB2aXRhZS4gRHVpcyB2ZXN0aWJ1 bHVtIGRpYW0gdWxsYW1jb3JwZXIgbWFzc2EgdmVzdGlidWx1bSwgdXQgYXVjdG9y IGxvcmVtIGltcGVyZGlldC4gVmVzdGlidWx1bSAKZXQgdmVuZW5hdGlzIHRlbGx1 cy4gU3VzcGVuZGlzc2UgY29udmFsbGlzLCBvZGlvIGFjIGRpY3R1bSBsYWNpbmlh LCBuZXF1ZSBxdWFtIHRpbmNpZHVudCByaXN1cywgbm9uIG9ybmFyZSBkb2xvciBs YWN1cyAKbmVjIHRlbGx1cy4gTWF1cmlzIHJob25jdXMgZmVybWVudHVtIG5lcXVl IHNpdCBhbWV0IHNvbGxpY2l0dWRpbi4gUGVsbGVudGVzcXVlIG51bGxhIG1hZ25h LCBjb21tb2RvIHZlbCB0aW5jaWR1bnQgc2VkLCAKaGVuZHJlcml0IHF1aXMganVz dG8uCgpJbiBoYWMgaGFiaXRhc3NlIHBsYXRlYSBkaWN0dW1zdC4gTnVuYyBldCBl c3QgYXVndWUuIFZpdmFtdXMgcHJldGl1bSwgb2RpbyB2ZWwgc29kYWxlcyBzZW1w ZXIsIHJpc3VzIGFudGUgZWxlbWVudHVtIAp1cm5hLCBhYyB1bGxhbWNvcnBlciBt YXNzYSBuZXF1ZSBub24gbGlndWxhLiBDcmFzIGlkIHRlbGx1cyBxdWlzIHVybmEg YWRpcGlzY2luZyBlbGVtZW50dW0uIERvbmVjIGFkaXBpc2NpbmcgbWFnbmEgdmVs IApzdXNjaXBpdCB2dWxwdXRhdGUuIFF1aXNxdWUgaW4gbWkgZWdldCBvcmNpIHZp dmVycmEgc2NlbGVyaXNxdWUgbmVjIGV0IG1hZ25hLiBDcmFzIHBvc3VlcmUsIHVy bmEgbGFjaW5pYSBkaWN0dW0gCnJob25jdXMsIGp1c3RvIG9yY2kgc3VzY2lwaXQg bWV0dXMsIHV0IGdyYXZpZGEgb3JjaSBudWxsYSBpbiB0dXJwaXMuIEludGVyZHVt IGV0IG1hbGVzdWFkYSBmYW1lcyBhYyBhbnRlIGlwc3VtIHByaW1pcyAKaW4gZmF1 Y2lidXMuIEluIHZvbHV0cGF0IGZldWdpYXQgdHVycGlzLCBub24gZmF1Y2lidXMg bnVuYyBpbnRlcmR1bSB1dC4gUHJhZXNlbnQgb3JuYXJlIHNhZ2l0dGlzIHVybmEs IGlkIGxhY2luaWEgCnRvcnRvciBzdXNjaXBpdCBldC4gUGVsbGVudGVzcXVlIHRl bXBvciBtaSBhYyBuaXNpIHZhcml1cywgdml0YWUgdWxsYW1jb3JwZXIgdXJuYSBz dXNjaXBpdC4KCkFsaXF1YW0gcGVsbGVudGVzcXVlIHZ1bHB1dGF0ZSB0dXJwaXMg dmVzdGlidWx1bSBlbGVpZmVuZC4gRG9uZWMgZmF1Y2lidXMgZXUgZmVsaXMgZXUg YmxhbmRpdC4gUGVsbGVudGVzcXVlIHB1bHZpbmFyLCAKZWxpdCBub24gbGFjaW5p YSBwb3J0dGl0b3IsIG9yY2kgbmliaCBpYWN1bGlzIGF1Z3VlLCBhYyBzY2VsZXJp c3F1ZSBtaSB0ZWxsdXMgcXVpcyB0b3J0b3IuIEludGVyZHVtIGV0IG1hbGVzdWFk YSBmYW1lcyAKYWMgYW50ZSBpcHN1bSBwcmltaXMgaW4gZmF1Y2lidXMuIENyYXMg bmVjIHN1c2NpcGl0IHJpc3VzLCB1dCB1bHRyaWNpZXMgZWxpdC4gU3VzcGVuZGlz c2UgZXQgZnJpbmdpbGxhIHVybmEuIERvbmVjIApsdWN0dXMgZXQgbmlzaSBxdWlz IGJpYmVuZHVtLiBRdWlzcXVlIHNlZCBhdWd1ZSBsYWNpbmlhLCBwZWxsZW50ZXNx dWUgZGlhbSB2aXRhZSwgY29udmFsbGlzIG1ldHVzLiBOYW0gdmVoaWN1bGEgbWV0 dXMgCmVnZXQgb3JjaSBzYWdpdHRpcyBzb2RhbGVzLgoKQ3VyYWJpdHVyIGVnZXN0 YXMgY29uZ3VlIG5pYmggc2VkIGx1Y3R1cy4gTmFtIGx1Y3R1cyB0ZWxsdXMgYXQg bnVsbGEgdmVzdGlidWx1bSwgcnV0cnVtIGZlcm1lbnR1bSBlc3QgdnVscHV0YXRl LiBOdWxsYSAKY29uZGltZW50dW0gZHVpIGEgZG9sb3IgbG9ib3J0aXMsIGV1IGFs aXF1ZXQgb2RpbyBwcmV0aXVtLiBQaGFzZWxsdXMgaWQgcHJldGl1bSBudWxsYS4g RG9uZWMgZXUgdGluY2lkdW50IGxlY3R1cywgaW4gCm9ybmFyZSBvcmNpLiBQZWxs ZW50ZXNxdWUgbW9sbGlzIGVzdCBlZ2V0IHR1cnBpcyBhbGlxdWV0LCB2ZWwgdGVt cG9yIHZlbGl0IGZyaW5naWxsYS4gQ3VyYWJpdHVyIGEgbGVvIGVsZW1lbnR1bSBl bGl0IApwZWxsZW50ZXNxdWUgdGluY2lkdW50IHZlc3RpYnVsdW0gc2l0IGFtZXQg bWkuIFZlc3RpYnVsdW0gdmFyaXVzIHB1bHZpbmFyIG5pc2kgc2l0IGFtZXQgZGln bmlzc2ltLiBWZXN0aWJ1bHVtIGR1aSAKdmVsaXQsIGNvbW1vZG8gdmVsIGF1Z3Vl IG5vbiwgZGFwaWJ1cyBpbXBlcmRpZXQgbWkuCgpFdGlhbSBhdCB0dXJwaXMgdmVs aXQuIFN1c3BlbmRpc3NlIHRlbXBvciwgbmlzbCBhIGNvbmd1ZSBwZWxsZW50ZXNx dWUsIGVyYXQgdGVsbHVzIGdyYXZpZGEgc2FwaWVuLCBldCBzb2RhbGVzIG51bGxh IApuaXNpIGF0IG1hdXJpcy4gTnVuYyBjb25zZWN0ZXR1ciBsaWd1bGEgdml0YWUg cG9zdWVyZSBwaGFyZXRyYS4gSW50ZWdlciBpZCBzdXNjaXBpdCBzZW0uIFByYWVz ZW50IGNyYXMgYW1ldC4=