├── .github
└── workflows
│ ├── build.yml
│ └── release.yml
├── .gitignore
├── .mvn
└── wrapper
│ └── maven-wrapper.properties
├── HEADER
├── LICENSE
├── README.md
├── SECURITY.md
├── jagged-api
├── pom.xml
└── src
│ ├── main
│ └── java
│ │ └── com
│ │ └── exceptionfactory
│ │ └── jagged
│ │ ├── DecryptingChannelFactory.java
│ │ ├── EncryptingChannelFactory.java
│ │ ├── FileKey.java
│ │ ├── PayloadException.java
│ │ ├── RecipientStanza.java
│ │ ├── RecipientStanzaReader.java
│ │ ├── RecipientStanzaWriter.java
│ │ └── UnsupportedRecipientStanzaException.java
│ └── test
│ └── java
│ └── com
│ └── exceptionfactory
│ └── jagged
│ └── FileKeyTest.java
├── jagged-bech32
├── pom.xml
└── src
│ ├── main
│ └── java
│ │ └── com
│ │ └── exceptionfactory
│ │ └── jagged
│ │ └── bech32
│ │ ├── Bech32.java
│ │ ├── Bech32Address.java
│ │ ├── SharedCoder.java
│ │ ├── StandardBech32Address.java
│ │ ├── StandardDecoder.java
│ │ └── StandardEncoder.java
│ └── test
│ └── java
│ └── com
│ └── exceptionfactory
│ └── jagged
│ └── bech32
│ └── Bech32Test.java
├── jagged-bom
└── pom.xml
├── jagged-framework
├── pom.xml
└── src
│ ├── main
│ └── java
│ │ └── com
│ │ └── exceptionfactory
│ │ └── jagged
│ │ └── framework
│ │ ├── armor
│ │ ├── ArmoredDecodingException.java
│ │ ├── ArmoredDecryptingChannelFactory.java
│ │ ├── ArmoredEncryptingChannelFactory.java
│ │ ├── ArmoredIndicator.java
│ │ ├── ArmoredReadableByteChannel.java
│ │ ├── ArmoredSeparator.java
│ │ └── ArmoredWritableByteChannel.java
│ │ ├── codec
│ │ ├── CanonicalBase64.java
│ │ ├── CanonicalBase64Decoder.java
│ │ ├── CanonicalBase64Encoder.java
│ │ └── CanonicalBase64OutputStream.java
│ │ ├── crypto
│ │ ├── ByteBufferCipherFactory.java
│ │ ├── ByteBufferDecryptor.java
│ │ ├── ByteBufferEncryptor.java
│ │ ├── CipherFactory.java
│ │ ├── CipherKey.java
│ │ ├── CryptographicAlgorithm.java
│ │ ├── CryptographicAlgorithmKey.java
│ │ ├── CryptographicKeyDescription.java
│ │ ├── CryptographicKeyType.java
│ │ ├── EncryptedFileKey.java
│ │ ├── FileKeyDecryptor.java
│ │ ├── FileKeyDecryptorFactory.java
│ │ ├── FileKeyEncryptor.java
│ │ ├── FileKeyEncryptorFactory.java
│ │ ├── FileKeyIvParameterSpec.java
│ │ ├── HashedDerivedKeyProducer.java
│ │ ├── HeaderKeyProducer.java
│ │ ├── HeaderKeyProducerFactory.java
│ │ ├── MacKey.java
│ │ ├── MessageAuthenticationCodeProducer.java
│ │ ├── MessageAuthenticationCodeProducerFactory.java
│ │ ├── PayloadIvParameterSpec.java
│ │ ├── PayloadKeyProducer.java
│ │ ├── PayloadKeyProducerFactory.java
│ │ ├── PayloadNonceKey.java
│ │ ├── SharedSaltKey.java
│ │ ├── SharedSecretKey.java
│ │ ├── StandardByteBufferCipherFactory.java
│ │ ├── StandardByteBufferDecryptor.java
│ │ ├── StandardByteBufferEncryptor.java
│ │ ├── StandardFileKeyDecryptor.java
│ │ ├── StandardFileKeyEncryptor.java
│ │ ├── StandardHeaderKeyProducer.java
│ │ ├── StandardMessageAuthenticationCodeProducer.java
│ │ └── StandardPayloadKeyProducer.java
│ │ ├── format
│ │ ├── AuthenticatedStandardFileHeaderWriter.java
│ │ ├── FileHeader.java
│ │ ├── FileHeaderReader.java
│ │ ├── FileHeaderWriter.java
│ │ ├── FileKeyReader.java
│ │ ├── HeaderDecodingException.java
│ │ ├── PayloadKeyReader.java
│ │ ├── PayloadKeyWriter.java
│ │ ├── SectionIndicator.java
│ │ ├── SectionSeparator.java
│ │ ├── StandardFileHeader.java
│ │ ├── StandardFileHeaderReader.java
│ │ ├── StandardFileHeaderWriter.java
│ │ ├── StandardFileKeyReader.java
│ │ ├── StandardPayloadKeyReader.java
│ │ ├── StandardPayloadKeyWriter.java
│ │ └── StandardRecipientStanza.java
│ │ └── stream
│ │ ├── ChunkSize.java
│ │ ├── DecryptingChannel.java
│ │ ├── EncryptingChannel.java
│ │ ├── StandardDecryptingChannelFactory.java
│ │ └── StandardEncryptingChannelFactory.java
│ └── test
│ └── java
│ └── com
│ └── exceptionfactory
│ └── jagged
│ └── framework
│ ├── armor
│ ├── ArmoredDecryptingChannelFactoryTest.java
│ ├── ArmoredEncryptingChannelFactoryTest.java
│ ├── ArmoredReadableByteChannelTest.java
│ └── ArmoredWritableByteChannelTest.java
│ ├── codec
│ ├── CanonicalBase64DecoderTest.java
│ └── CanonicalBase64EncoderTest.java
│ ├── crypto
│ ├── CipherFactoryTest.java
│ ├── CipherKeyTest.java
│ ├── FileKeyIvParameterSpecTest.java
│ ├── HeaderKeyProducerFactoryTest.java
│ ├── MacKeyTest.java
│ ├── MessageAuthenticationCodeProducerFactoryTest.java
│ ├── PayloadIvParameterSpecTest.java
│ ├── PayloadKeyProducerFactoryTest.java
│ ├── SharedSaltKeyTest.java
│ ├── SharedSecretKeyTest.java
│ ├── StandardByteBufferCipherFactoryTest.java
│ ├── StandardByteBufferDecryptorTest.java
│ ├── StandardByteBufferEncryptorTest.java
│ ├── StandardFileKeyDecryptorTest.java
│ ├── StandardFileKeyEncryptorTest.java
│ ├── StandardHeaderKeyProducerTest.java
│ ├── StandardMessageAuthenticationCodeProducerTest.java
│ └── StandardPayloadKeyProducerTest.java
│ ├── format
│ ├── StandardFileHeaderReaderTest.java
│ ├── StandardFileKeyHeaderTest.java
│ ├── StandardPayloadKeyReaderTest.java
│ └── StandardPayloadKeyWriterTest.java
│ └── stream
│ ├── DecryptingChannelTest.java
│ ├── EncryptingChannelTest.java
│ ├── StandardDecryptingChannelFactoryTest.java
│ └── StandardEncryptingChannelFactoryTest.java
├── jagged-scrypt
├── pom.xml
└── src
│ ├── main
│ └── java
│ │ └── com
│ │ └── exceptionfactory
│ │ └── jagged
│ │ └── scrypt
│ │ ├── DerivedWrapKeyProducer.java
│ │ ├── PasswordBasedKeyDerivationFunction2.java
│ │ ├── RecipientIndicator.java
│ │ ├── Salsa20RoundReducedFunction.java
│ │ ├── ScryptDerivedWrapKeyProducer.java
│ │ ├── ScryptFunction.java
│ │ ├── ScryptRecipientStanza.java
│ │ ├── ScryptRecipientStanzaReader.java
│ │ ├── ScryptRecipientStanzaReaderFactory.java
│ │ ├── ScryptRecipientStanzaWriter.java
│ │ └── ScryptRecipientStanzaWriterFactory.java
│ └── test
│ └── java
│ └── com
│ └── exceptionfactory
│ └── jagged
│ └── scrypt
│ ├── PasswordBasedKeyDerivationFunction2Test.java
│ ├── Salsa20RoundReducedFunctionTest.java
│ ├── ScryptDerivedWrapKeyProducerTest.java
│ ├── ScryptFunctionTest.java
│ ├── ScryptRecipientStanzaReaderFactoryTest.java
│ ├── ScryptRecipientStanzaReaderTest.java
│ ├── ScryptRecipientStanzaWriterFactoryTest.java
│ └── ScryptRecipientStanzaWriterTest.java
├── jagged-ssh
├── pom.xml
└── src
│ ├── main
│ └── java
│ │ └── com
│ │ └── exceptionfactory
│ │ └── jagged
│ │ └── ssh
│ │ ├── Ed25519KeyConverter.java
│ │ ├── Ed25519KeyIndicator.java
│ │ ├── Ed25519PrivateKey.java
│ │ ├── Ed25519PublicKey.java
│ │ ├── EllipticCurveKeyType.java
│ │ ├── EmptyInputKey.java
│ │ ├── KeyPairReader.java
│ │ ├── KeySeparator.java
│ │ ├── OpenSshKeyByteBufferReader.java
│ │ ├── OpenSshKeyIndicator.java
│ │ ├── OpenSshKeyPairReader.java
│ │ ├── PublicKeyFingerprintProducer.java
│ │ ├── PublicKeyMarshaller.java
│ │ ├── PublicKeyReader.java
│ │ ├── RsaOaepCipherFactory.java
│ │ ├── RsaPublicKeyFactory.java
│ │ ├── SharedSecretKeyProducer.java
│ │ ├── SharedWrapKeyProducer.java
│ │ ├── SshEd25519DerivedKey.java
│ │ ├── SshEd25519KeyType.java
│ │ ├── SshEd25519MarshalledKey.java
│ │ ├── SshEd25519OpenSshKeyPairReader.java
│ │ ├── SshEd25519PublicKeyMarshaller.java
│ │ ├── SshEd25519PublicKeyReader.java
│ │ ├── SshEd25519RecipientIndicator.java
│ │ ├── SshEd25519RecipientStanza.java
│ │ ├── SshEd25519RecipientStanzaReader.java
│ │ ├── SshEd25519RecipientStanzaReaderFactory.java
│ │ ├── SshEd25519RecipientStanzaWriter.java
│ │ ├── SshEd25519RecipientStanzaWriterFactory.java
│ │ ├── SshEd25519SharedWrapKeyProducer.java
│ │ ├── SshKeyType.java
│ │ ├── SshPublicKeyReader.java
│ │ ├── SshRsaOpenSshKeyPairReader.java
│ │ ├── SshRsaPublicKeyMarshaller.java
│ │ ├── SshRsaPublicKeyReader.java
│ │ ├── SshRsaRecipientIndicator.java
│ │ ├── SshRsaRecipientStanza.java
│ │ ├── SshRsaRecipientStanzaReader.java
│ │ ├── SshRsaRecipientStanzaReaderFactory.java
│ │ ├── SshRsaRecipientStanzaWriter.java
│ │ ├── SshRsaRecipientStanzaWriterFactory.java
│ │ ├── StandardEd25519KeyConverter.java
│ │ ├── StandardPublicKeyFingerprintProducer.java
│ │ ├── StandardRsaPublicKeyFactory.java
│ │ ├── X25519BasePointPublicKey.java
│ │ ├── X25519KeyAgreementFactory.java
│ │ ├── X25519KeyPairGeneratorFactory.java
│ │ ├── X25519SharedSecretKeyProducer.java
│ │ └── X25519SharedWrapKeyProducer.java
│ └── test
│ └── java
│ └── com
│ └── exceptionfactory
│ └── jagged
│ └── ssh
│ ├── Ed25519KeyPairProvider.java
│ ├── OpenSshKeyPairReaderTest.java
│ ├── RsaKeyPairProvider.java
│ ├── SshEd25519OpenSshKeyPairReaderTest.java
│ ├── SshEd25519PublicKeyMarshallerTest.java
│ ├── SshEd25519PublicKeyReaderTest.java
│ ├── SshEd25519RecipientStanzaReaderFactoryTest.java
│ ├── SshEd25519RecipientStanzaReaderTest.java
│ ├── SshEd25519RecipientStanzaWriterFactoryTest.java
│ ├── SshRsaOpenSshKeyPairReaderTest.java
│ ├── SshRsaPublicKeyMarshallerTest.java
│ ├── SshRsaPublicKeyReaderTest.java
│ ├── SshRsaRecipientStanzaReaderFactoryTest.java
│ ├── SshRsaRecipientStanzaReaderTest.java
│ ├── SshRsaRecipientStanzaWriterFactoryTest.java
│ ├── SshRsaRecipientStanzaWriterTest.java
│ ├── StandardEd25519KeyConverterTest.java
│ ├── StandardPublicKeyFingerprintProducerTest.java
│ ├── X25519BasePointPublicKeyTest.java
│ ├── X25519KeyAgreementFactoryTest.java
│ ├── X25519KeyPairGeneratorFactoryTest.java
│ └── X25519SharedSecretKeyProducerTest.java
├── jagged-test
├── pom.xml
└── src
│ └── test
│ ├── java
│ └── com
│ │ └── exceptionfactory
│ │ └── jagged
│ │ └── test
│ │ ├── CommunityCryptographyExpectation.java
│ │ ├── CommunityCryptographyProperty.java
│ │ ├── CommunityCryptographyTest.java
│ │ └── FrameworkTest.java
│ └── resources
│ └── java.security
├── jagged-x25519
├── pom.xml
└── src
│ ├── main
│ └── java
│ │ └── com
│ │ └── exceptionfactory
│ │ └── jagged
│ │ └── x25519
│ │ ├── BasePointPublicKey.java
│ │ ├── IdentityIndicator.java
│ │ ├── KeyAgreementFactory.java
│ │ ├── KeyPairGeneratorFactory.java
│ │ ├── RecipientIndicator.java
│ │ ├── RecipientKeyFactory.java
│ │ ├── RecipientKeyType.java
│ │ ├── SharedSecretKeyProducer.java
│ │ ├── SharedWrapKeyProducer.java
│ │ ├── StandardRecipientKeyFactory.java
│ │ ├── X25519KeyFactory.java
│ │ ├── X25519KeyFactorySpi.java
│ │ ├── X25519KeyPairGenerator.java
│ │ ├── X25519PrivateKey.java
│ │ ├── X25519PublicKey.java
│ │ ├── X25519RecipientStanza.java
│ │ ├── X25519RecipientStanzaReader.java
│ │ ├── X25519RecipientStanzaReaderFactory.java
│ │ ├── X25519RecipientStanzaWriter.java
│ │ ├── X25519RecipientStanzaWriterFactory.java
│ │ ├── X25519SharedSecretKeyProducer.java
│ │ └── X25519SharedWrapKeyProducer.java
│ └── test
│ └── java
│ └── com
│ └── exceptionfactory
│ └── jagged
│ └── x25519
│ ├── BasePointPublicKeyTest.java
│ ├── KeyAgreementFactoryTest.java
│ ├── KeyPairGeneratorFactoryTest.java
│ ├── StandardRecipientKeyFactoryTest.java
│ ├── X25519KeyFactoryTest.java
│ ├── X25519KeyPairGeneratorTest.java
│ ├── X25519RecipientStanzaReaderFactoryTest.java
│ ├── X25519RecipientStanzaReaderTest.java
│ ├── X25519RecipientStanzaTest.java
│ ├── X25519RecipientStanzaWriterFactoryTest.java
│ ├── X25519RecipientStanzaWriterTest.java
│ ├── X25519SharedSecretKeyProducerTest.java
│ └── X25519SharedWrapKeyProducerTest.java
├── mvnw
├── mvnw.cmd
└── pom.xml
/.github/workflows/build.yml:
--------------------------------------------------------------------------------
1 | name: build
2 |
3 | on:
4 | push:
5 | branches:
6 | - main
7 | pull_request:
8 | branches:
9 | - main
10 |
11 | permissions:
12 | security-events: write
13 | contents: read
14 |
15 | jobs:
16 | build-java-21:
17 | runs-on: ubuntu-latest
18 | name: Java 21
19 | steps:
20 | - name: Checkout Sources
21 | uses: actions/checkout@v4
22 | - name: Initialize CodeQL
23 | uses: github/codeql-action/init@v3
24 | with:
25 | languages: java
26 | - name: Setup Java JDK
27 | uses: actions/setup-java@v4
28 | with:
29 | java-version: '21'
30 | distribution: 'zulu'
31 | cache: 'maven'
32 | - name: Build
33 | run: ./mvnw --batch-mode --update-snapshots verify
34 | - name: Perform CodeQL Analysis
35 | uses: github/codeql-action/analyze@v3
36 | - name: Codecov
37 | uses: codecov/codecov-action@v4
38 | with:
39 | token: ${{ secrets.CODECOV_TOKEN }}
40 | build-java-17:
41 | runs-on: ubuntu-latest
42 | name: Java 17
43 | steps:
44 | - name: Checkout Sources
45 | uses: actions/checkout@v4
46 | - name: Setup Java JDK
47 | uses: actions/setup-java@v4
48 | with:
49 | java-version: '17'
50 | distribution: 'zulu'
51 | cache: 'maven'
52 | - name: Build
53 | run: ./mvnw --batch-mode --update-snapshots verify
54 | build-java-11:
55 | runs-on: ubuntu-latest
56 | name: Java 11
57 | steps:
58 | - name: Checkout Sources
59 | uses: actions/checkout@v4
60 | - name: Setup Java JDK
61 | uses: actions/setup-java@v4
62 | with:
63 | java-version: '11'
64 | distribution: 'zulu'
65 | cache: 'maven'
66 | - name: Build
67 | run: ./mvnw --batch-mode --update-snapshots verify
68 | build-java-8:
69 | runs-on: ubuntu-latest
70 | name: Java 8
71 | steps:
72 | - name: Checkout Sources
73 | uses: actions/checkout@v4
74 | - name: Setup Java JDK
75 | uses: actions/setup-java@v4
76 | with:
77 | java-version: '8'
78 | distribution: 'zulu'
79 | cache: 'maven'
80 | - name: Build
81 | run: ./mvnw --batch-mode --update-snapshots verify
82 |
--------------------------------------------------------------------------------
/.github/workflows/release.yml:
--------------------------------------------------------------------------------
1 | name: release
2 |
3 | on:
4 | workflow_dispatch:
5 |
6 | permissions:
7 | contents: read
8 |
9 | jobs:
10 | release:
11 | runs-on: ubuntu-latest
12 | steps:
13 | - name: Checkout Sources
14 | uses: actions/checkout@v4
15 | with:
16 | fetch-depth: 0
17 | - name: Setup Java JDK
18 | uses: actions/setup-java@v4
19 | with:
20 | java-version: '17'
21 | distribution: 'zulu'
22 | cache: 'maven'
23 | - name: Stage Artifacts
24 | run: ./mvnw --batch-mode deploy
25 | - name: Release
26 | run: ./mvnw --batch-mode jreleaser:sign jreleaser:deploy
27 | env:
28 | JRELEASER_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
29 | JRELEASER_GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }}
30 | JRELEASER_GPG_PUBLIC_KEY: ${{ secrets.GPG_PUBLIC_KEY }}
31 | JRELEASER_GPG_SECRET_KEY: ${{ secrets.GPG_SECRET_KEY }}
32 | JRELEASER_NEXUS2_USERNAME: ${{ secrets.NEXUS2_USERNAME }}
33 | JRELEASER_NEXUS2_PASSWORD: ${{ secrets.NEXUS2_PASSWORD }}
34 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Compiled class file
2 | *.class
3 | target/
4 |
5 | # Log file
6 | *.log
7 |
8 | # BlueJ files
9 | *.ctxt
10 |
11 | # Mobile Tools for Java (J2ME)
12 | .mtj.tmp/
13 |
14 | # Package Files #
15 | *.jar
16 | *.war
17 | *.nar
18 | *.ear
19 | *.zip
20 | *.tar.gz
21 | *.rar
22 |
23 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
24 | hs_err_pid*
25 |
26 | # IntelliJ
27 | .idea/
28 |
--------------------------------------------------------------------------------
/.mvn/wrapper/maven-wrapper.properties:
--------------------------------------------------------------------------------
1 | # Licensed to the Apache Software Foundation (ASF) under one
2 | # or more contributor license agreements. See the NOTICE file
3 | # distributed with this work for additional information
4 | # regarding copyright ownership. The ASF licenses this file
5 | # to you under the Apache License, Version 2.0 (the
6 | # "License"); you may not use this file except in compliance
7 | # with the License. You may obtain a copy of the License at
8 | #
9 | # http://www.apache.org/licenses/LICENSE-2.0
10 | #
11 | # Unless required by applicable law or agreed to in writing,
12 | # software distributed under the License is distributed on an
13 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 | # KIND, either express or implied. See the License for the
15 | # specific language governing permissions and limitations
16 | # under the License.
17 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.9/apache-maven-3.9.9-bin.zip
18 | wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.3.2/maven-wrapper-3.3.2.jar
19 |
--------------------------------------------------------------------------------
/HEADER:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Jagged Contributors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
--------------------------------------------------------------------------------
/SECURITY.md:
--------------------------------------------------------------------------------
1 | # Security Policy
2 |
3 | ## Reporting Vulnerabilities
4 |
5 | The project welcomes responsible reporting of security issues.
6 |
7 | Please allow a reasonable amount of time for evaluation of reported vulnerabilities.
8 |
9 | Vulnerability reports should include the following information:
10 |
11 | - Summary of the problem
12 | - Details of the problem including platform and version information
13 | - Proof of concept to reproduce the problem
14 | - Impact of the problem
15 |
16 | ## Reporting Methods
17 |
18 | Please report vulnerabilities using
19 | [GitHub Security Advisories](https://github.com/exceptionfactory/jagged/security/advisories/new) for initial evaluation
20 | from project maintainers.
21 |
--------------------------------------------------------------------------------
/jagged-api/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 |
8 | com.exceptionfactory.jagged
9 | jagged
10 | 1.0.1-SNAPSHOT
11 |
12 |
13 | jagged-api
14 | jagged-api
15 | Jagged public interface components for age encryption
16 | https://github.com/exceptionfactory/jagged
17 |
18 |
19 |
20 | org.junit.jupiter
21 | junit-jupiter-api
22 | test
23 |
24 |
25 |
26 |
27 |
28 |
29 | org.apache.maven.plugins
30 | maven-jar-plugin
31 |
32 |
33 |
34 | ${project.groupId}
35 |
36 |
37 |
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/jagged-api/src/main/java/com/exceptionfactory/jagged/DecryptingChannelFactory.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Jagged Contributors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.exceptionfactory.jagged;
17 |
18 | import java.io.IOException;
19 | import java.nio.channels.ReadableByteChannel;
20 | import java.security.GeneralSecurityException;
21 |
22 | /**
23 | * Abstraction for creating readable Channels supporting streaming age decryption
24 | */
25 | public interface DecryptingChannelFactory {
26 | /**
27 | * Create new channel that reads and decrypts from the supplied input channel
28 | *
29 | * @param inputChannel Input Channel source containing encrypted bytes
30 | * @param recipientStanzaReaders Recipient Stanza Readers capable of providing the Identity to read the File Key for decryption
31 | * @return Readable Byte Channel containing decrypted bytes
32 | * @throws GeneralSecurityException Thrown on failures while processing recipients or performing cipher operations
33 | * @throws IOException Thrown on failures to read Channel or Recipient Stanzas
34 | */
35 | ReadableByteChannel newDecryptingChannel(
36 | ReadableByteChannel inputChannel,
37 | Iterable recipientStanzaReaders
38 | ) throws GeneralSecurityException, IOException;
39 | }
40 |
--------------------------------------------------------------------------------
/jagged-api/src/main/java/com/exceptionfactory/jagged/EncryptingChannelFactory.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Jagged Contributors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.exceptionfactory.jagged;
17 |
18 | import java.io.IOException;
19 | import java.nio.channels.WritableByteChannel;
20 | import java.security.GeneralSecurityException;
21 |
22 | /**
23 | * Abstraction for creating writable Channels supporting streaming age encryption
24 | */
25 | public interface EncryptingChannelFactory {
26 | /**
27 | * Create new channel that encrypts and writes to the supplied output channel
28 | *
29 | * @param outputChannel Output Channel destination for encrypted bytes
30 | * @param recipientStanzaWriters One or more Recipient Stanza Writers for intended recipients
31 | * @return Writable Byte Channel for encrypted bytes
32 | * @throws GeneralSecurityException Thrown on failures writing recipients or performing cipher operations
33 | * @throws IOException Thrown on failures to write Channel or Recipient Stanzas
34 | */
35 | WritableByteChannel newEncryptingChannel(
36 | WritableByteChannel outputChannel,
37 | Iterable recipientStanzaWriters
38 | ) throws GeneralSecurityException, IOException;
39 | }
40 |
--------------------------------------------------------------------------------
/jagged-api/src/main/java/com/exceptionfactory/jagged/PayloadException.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Jagged Contributors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.exceptionfactory.jagged;
17 |
18 | import java.io.IOException;
19 |
20 | /**
21 | * Payload Exception indicating problems reading or writing File Payload
22 | */
23 | public class PayloadException extends IOException {
24 | /**
25 | * Payload Exception with message
26 | *
27 | * @param message Message describing the problem with the Payload
28 | */
29 | public PayloadException(final String message) {
30 | super(message);
31 | }
32 |
33 | /**
34 | * Payload Exception with message and cause
35 | *
36 | * @param message Message describing the problem with the Payload
37 | * @param cause Throwable cause for the Payload Exception
38 | */
39 | public PayloadException(final String message, final Throwable cause) {
40 | super(message, cause);
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/jagged-api/src/main/java/com/exceptionfactory/jagged/RecipientStanza.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Jagged Contributors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.exceptionfactory.jagged;
17 |
18 | import java.util.List;
19 |
20 | /**
21 | * Recipient Stanza describes a section of the age header encapsulating the information required to derive a File Key
22 | */
23 | public interface RecipientStanza {
24 | /**
25 | * Get Recipient Stanza Type returns the first argument from the header section
26 | *
27 | * @return Recipient Stanza Type
28 | */
29 | String getType();
30 |
31 | /**
32 | * Get zero or more Recipient Stanza arguments located after the Stanza Type in the header section
33 | *
34 | * @return Recipient Stanza Arguments
35 | */
36 | List getArguments();
37 |
38 | /**
39 | * Get Recipient Stanza Body decoded from Base64 representation in header section
40 | *
41 | * @return Recipient Stanza Body
42 | */
43 | byte[] getBody();
44 | }
45 |
--------------------------------------------------------------------------------
/jagged-api/src/main/java/com/exceptionfactory/jagged/RecipientStanzaReader.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Jagged Contributors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.exceptionfactory.jagged;
17 |
18 | import java.security.GeneralSecurityException;
19 |
20 | /**
21 | * Identity abstraction for reading Recipient Stanzas and returning a File Key
22 | */
23 | public interface RecipientStanzaReader {
24 | /**
25 | * Get File Key reads one or more Recipient Stanzas and return a File Key of 16 bytes
26 | *
27 | * @param recipientStanzas One or more Recipient Stanzas parsed from the age file header
28 | * @return File Key decrypted from matching Recipient Stanza in age file header
29 | * @throws GeneralSecurityException Thrown on failure to decrypt File Key or process Recipient Stanzas
30 | */
31 | FileKey getFileKey(Iterable recipientStanzas) throws GeneralSecurityException;
32 | }
33 |
--------------------------------------------------------------------------------
/jagged-api/src/main/java/com/exceptionfactory/jagged/RecipientStanzaWriter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Jagged Contributors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.exceptionfactory.jagged;
17 |
18 | import java.security.GeneralSecurityException;
19 |
20 | /**
21 | * Recipient abstraction for reading a File Key and writing a Recipient Stanza with wrapped key arguments
22 | */
23 | public interface RecipientStanzaWriter {
24 | /**
25 | * Get Recipient Stanzas wrapping a File Key of 16 bytes
26 | *
27 | * @param fileKey File Key
28 | * @return Recipient Stanzas with wrapped key arguments
29 | * @throws GeneralSecurityException Thrown failures to write a Recipient Stanzas from the File Key
30 | */
31 | Iterable getRecipientStanzas(FileKey fileKey) throws GeneralSecurityException;
32 | }
33 |
--------------------------------------------------------------------------------
/jagged-api/src/main/java/com/exceptionfactory/jagged/UnsupportedRecipientStanzaException.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Jagged Contributors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.exceptionfactory.jagged;
17 |
18 | import java.security.GeneralSecurityException;
19 |
20 | /**
21 | * Unsupported Recipient Stanza Exception indicating incorrect formatting or no matched Recipient Stanza found in age file header
22 | */
23 | public class UnsupportedRecipientStanzaException extends GeneralSecurityException {
24 | /**
25 | * Unsupported Recipient Stanza Exception constructor with message providing additional details
26 | *
27 | * @param message Message providing additional details
28 | */
29 | public UnsupportedRecipientStanzaException(final String message) {
30 | super(message);
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/jagged-bech32/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 |
8 | com.exceptionfactory.jagged
9 | jagged
10 | 1.0.1-SNAPSHOT
11 |
12 |
13 | jagged-bech32
14 | jagged-bech32
15 | Jagged Bech32 encoding for age encryption
16 | https://github.com/exceptionfactory/jagged
17 |
18 |
19 |
20 | org.junit.jupiter
21 | junit-jupiter-api
22 | test
23 |
24 |
25 |
26 |
27 |
28 |
29 | org.apache.maven.plugins
30 | maven-jar-plugin
31 |
32 |
33 |
34 | ${project.groupId}.bech32
35 |
36 |
37 |
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/jagged-bech32/src/main/java/com/exceptionfactory/jagged/bech32/Bech32Address.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Jagged Contributors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.exceptionfactory.jagged.bech32;
17 |
18 | /**
19 | * Bech32 Address containing the human-readable part and the data without the separator or checksum
20 | */
21 | public interface Bech32Address {
22 | /**
23 | * Get the human-readable part of the address prior to the separator
24 | *
25 | * @return Human-readable part of the address
26 | */
27 | CharSequence getHumanReadablePart();
28 |
29 | /**
30 | * Get the data portion of the address after the separator but without the trailing checksum
31 | *
32 | * @return Data portion of the address
33 | */
34 | byte[] getData();
35 | }
36 |
--------------------------------------------------------------------------------
/jagged-bech32/src/main/java/com/exceptionfactory/jagged/bech32/StandardBech32Address.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Jagged Contributors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.exceptionfactory.jagged.bech32;
17 |
18 | import java.util.Objects;
19 |
20 | /**
21 | * Standard implementation of Bech32 Address
22 | */
23 | class StandardBech32Address implements Bech32Address {
24 | private final CharSequence humanReadablePart;
25 |
26 | private final byte[] data;
27 |
28 | /**
29 | * Standard constructor with required properties
30 | *
31 | * @param humanReadablePart Human-Readable Part characters
32 | * @param data Data bytes
33 | */
34 | StandardBech32Address(final CharSequence humanReadablePart, final byte[] data) {
35 | this.humanReadablePart = Objects.requireNonNull(humanReadablePart, "Human-Readable Part required");
36 | this.data = Objects.requireNonNull(data, "Data required");
37 | }
38 |
39 | /**
40 | * Get Human-Readable Part characters
41 | *
42 | * @return Human-Readable Part
43 | */
44 | @Override
45 | public CharSequence getHumanReadablePart() {
46 | return humanReadablePart;
47 | }
48 |
49 | /**
50 | * Get Data decoded bytes without checksum
51 | *
52 | * @return Data bytes
53 | */
54 | @Override
55 | public byte[] getData() {
56 | return data.clone();
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/jagged-bom/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 |
8 | com.exceptionfactory.jagged
9 | jagged
10 | 1.0.1-SNAPSHOT
11 |
12 |
13 | jagged-bom
14 | jagged-bom
15 | pom
16 | Jagged Bill of Materials for age encryption
17 | https://github.com/exceptionfactory/jagged
18 |
19 |
20 |
21 |
22 | com.exceptionfactory.jagged
23 | jagged-api
24 | 1.0.1-SNAPSHOT
25 |
26 |
27 | com.exceptionfactory.jagged
28 | jagged-framework
29 | 1.0.1-SNAPSHOT
30 |
31 |
32 | com.exceptionfactory.jagged
33 | jagged-scrypt
34 | 1.0.1-SNAPSHOT
35 |
36 |
37 | com.exceptionfactory.jagged
38 | jagged-ssh
39 | 1.0.1-SNAPSHOT
40 |
41 |
42 | com.exceptionfactory.jagged
43 | jagged-bech32
44 | 1.0.1-SNAPSHOT
45 |
46 |
47 | com.exceptionfactory.jagged
48 | jagged-x25519
49 | 1.0.1-SNAPSHOT
50 |
51 |
52 |
53 |
54 |
--------------------------------------------------------------------------------
/jagged-framework/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 |
8 | com.exceptionfactory.jagged
9 | jagged
10 | 1.0.1-SNAPSHOT
11 |
12 |
13 | jagged-framework
14 | jagged-framework
15 | Jagged framework components for age encryption
16 | https://github.com/exceptionfactory/jagged
17 |
18 |
19 |
20 | com.exceptionfactory.jagged
21 | jagged-api
22 |
23 |
24 | org.junit.jupiter
25 | junit-jupiter-api
26 | test
27 |
28 |
29 | org.mockito
30 | mockito-core
31 | test
32 |
33 |
34 | org.mockito
35 | mockito-junit-jupiter
36 | test
37 |
38 |
39 |
40 |
41 |
42 |
43 | org.apache.maven.plugins
44 | maven-jar-plugin
45 |
46 |
47 |
48 | ${project.groupId}.framework
49 |
50 |
51 |
52 |
53 |
54 |
55 |
--------------------------------------------------------------------------------
/jagged-framework/src/main/java/com/exceptionfactory/jagged/framework/armor/ArmoredDecodingException.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Jagged Contributors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.exceptionfactory.jagged.framework.armor;
17 |
18 | import java.io.IOException;
19 |
20 | /**
21 | * Armored Decoding Exception indicates failures while reading age encryption armored messages
22 | */
23 | public class ArmoredDecodingException extends IOException {
24 | /**
25 | * Armored Decoding Exception with required message indicating problem details
26 | *
27 | * @param message Exception message with problem details
28 | */
29 | public ArmoredDecodingException(final String message) {
30 | super(message);
31 | }
32 |
33 | /**
34 | * Armored Decoding Exception with required message indicating problem details
35 | *
36 | * @param message Exception message with problem details
37 | * @param cause Throwable cause of armored decoding failures
38 | */
39 | public ArmoredDecodingException(final String message, final Throwable cause) {
40 | super(message, cause);
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/jagged-framework/src/main/java/com/exceptionfactory/jagged/framework/armor/ArmoredIndicator.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Jagged Contributors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.exceptionfactory.jagged.framework.armor;
17 |
18 | import java.nio.charset.StandardCharsets;
19 |
20 | /**
21 | * age-encryption Armored Indicator for header and footer information
22 | */
23 | enum ArmoredIndicator {
24 | /** PEM Header */
25 | HEADER("-----BEGIN AGE ENCRYPTED FILE-----"),
26 |
27 | /** PEM Footer */
28 | FOOTER("-----END AGE ENCRYPTED FILE-----");
29 |
30 | private final byte[] indicator;
31 |
32 | ArmoredIndicator(final String indicator) {
33 | this.indicator = indicator.getBytes(StandardCharsets.UTF_8);
34 | }
35 |
36 | byte[] getIndicator() {
37 | return indicator;
38 | }
39 |
40 | int getLength() {
41 | return indicator.length;
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/jagged-framework/src/main/java/com/exceptionfactory/jagged/framework/armor/ArmoredSeparator.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Jagged Contributors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.exceptionfactory.jagged.framework.armor;
17 |
18 | /**
19 | * age-encryption Armored Separator for encoded elements
20 | */
21 | enum ArmoredSeparator {
22 | /** Line Feed Character */
23 | LINE_FEED(10),
24 |
25 | /** Carriage Return Character */
26 | CARRIAGE_RETURN(13);
27 |
28 | private final byte code;
29 |
30 | ArmoredSeparator(final int code) {
31 | this.code = (byte) code;
32 | }
33 |
34 | byte getCode() {
35 | return code;
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/jagged-framework/src/main/java/com/exceptionfactory/jagged/framework/codec/CanonicalBase64Encoder.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Jagged Contributors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.exceptionfactory.jagged.framework.codec;
17 |
18 | import java.util.Base64;
19 | import java.util.Objects;
20 |
21 | /**
22 | * Canonical implementation of Base64 Encoder does not include padding
23 | */
24 | class CanonicalBase64Encoder implements CanonicalBase64.Encoder {
25 | private static final Base64.Encoder ENCODER_WITHOUT_PADDING = Base64.getEncoder().withoutPadding();
26 |
27 | /**
28 | * Encode byte array as Base64 characters from standard byte array
29 | *
30 | * @param source Sequence of bytes to be encoded
31 | * @return Base64 encoded byte array
32 | * @throws IllegalArgumentException Thrown when encountering invalid sources
33 | */
34 | @Override
35 | public byte[] encode(final byte[] source) {
36 | Objects.requireNonNull(source, "Source required for encoding");
37 | return ENCODER_WITHOUT_PADDING.encode(source);
38 | }
39 |
40 | /**
41 | * Encode byte array to Base64 character string from standard byte array
42 | *
43 | * @param source Sequence of bytes to be encoded
44 | * @return Base64 encoded string
45 | * @throws IllegalArgumentException Thrown when encountering invalid sources
46 | */
47 | @Override
48 | public String encodeToString(final byte[] source) {
49 | Objects.requireNonNull(source, "Source required for encoding");
50 | return ENCODER_WITHOUT_PADDING.encodeToString(source);
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/jagged-framework/src/main/java/com/exceptionfactory/jagged/framework/crypto/ByteBufferCipherFactory.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Jagged Contributors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.exceptionfactory.jagged.framework.crypto;
17 |
18 | import javax.crypto.spec.IvParameterSpec;
19 | import java.security.GeneralSecurityException;
20 |
21 | /**
22 | * Byte Buffer Cipher Factory provides instances of Byte Buffer Decryptor and Encryptor objects
23 | */
24 | public interface ByteBufferCipherFactory {
25 | /**
26 | * Create new instance of Byte Buffer Decryptor using provided Key and Initialization Vector
27 | *
28 | * @param cipherKey Cipher Key required
29 | * @param parameterSpec Initialization Vector parameter specification required
30 | * @return Byte Buffer Decryptor
31 | * @throws GeneralSecurityException Thrown on decryptor initialization failures
32 | */
33 | ByteBufferDecryptor newByteBufferDecryptor(CipherKey cipherKey, IvParameterSpec parameterSpec) throws GeneralSecurityException;
34 |
35 | /**
36 | * Create new instance of Byte Buffer Encryptor using provided Key and Initialization Vector
37 | *
38 | * @param cipherKey Cipher Key required
39 | * @param parameterSpec Initialization Vector parameter specification required
40 | * @return Byte Buffer Encryptor
41 | * @throws GeneralSecurityException Thrown on encryptor initialization failures
42 | */
43 | ByteBufferEncryptor newByteBufferEncryptor(CipherKey cipherKey, IvParameterSpec parameterSpec) throws GeneralSecurityException;
44 | }
45 |
--------------------------------------------------------------------------------
/jagged-framework/src/main/java/com/exceptionfactory/jagged/framework/crypto/ByteBufferDecryptor.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Jagged Contributors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.exceptionfactory.jagged.framework.crypto;
17 |
18 | import java.nio.ByteBuffer;
19 | import java.security.GeneralSecurityException;
20 |
21 | /**
22 | * Byte Buffer Decryptor abstracts Cipher decryption operations
23 | */
24 | public interface ByteBufferDecryptor {
25 | /**
26 | * Read encrypted input buffer and write decrypted bytes to output buffer
27 | *
28 | * @param inputBuffer Encrypted Input Byte Buffer
29 | * @param outputBuffer Decrypted Output Byte Buffer
30 | * @return Number of bytes stored in Output Byte Buffer
31 | * @throws GeneralSecurityException Thrown on decryption failures
32 | */
33 | int decrypt(ByteBuffer inputBuffer, ByteBuffer outputBuffer) throws GeneralSecurityException;
34 | }
35 |
--------------------------------------------------------------------------------
/jagged-framework/src/main/java/com/exceptionfactory/jagged/framework/crypto/ByteBufferEncryptor.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Jagged Contributors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.exceptionfactory.jagged.framework.crypto;
17 |
18 | import java.nio.ByteBuffer;
19 | import java.security.GeneralSecurityException;
20 |
21 | /**
22 | * Byte Buffer Encryptor abstracts Cipher encryption operations
23 | */
24 | public interface ByteBufferEncryptor {
25 | /**
26 | * Read input buffer and write encrypted bytes to output buffer
27 | *
28 | * @param inputBuffer Input Byte Buffer
29 | * @param outputBuffer Encrypted Output Byte Buffer
30 | * @return Number of bytes stored in Output Byte Buffer
31 | * @throws GeneralSecurityException Thrown on encryption failures
32 | */
33 | int encrypt(ByteBuffer inputBuffer, ByteBuffer outputBuffer) throws GeneralSecurityException;
34 | }
35 |
--------------------------------------------------------------------------------
/jagged-framework/src/main/java/com/exceptionfactory/jagged/framework/crypto/CipherKey.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Jagged Contributors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.exceptionfactory.jagged.framework.crypto;
17 |
18 | /**
19 | * Cipher Key extension of Cryptographic Algorithm Key with ChaCha20-Poly1305
20 | */
21 | public final class CipherKey extends CryptographicAlgorithmKey {
22 | /**
23 | * Cipher Key constructor with required symmetric key
24 | *
25 | * @param key Symmetric Key consisting of 32 bytes
26 | */
27 | public CipherKey(final byte[] key) {
28 | super(key, CryptographicKeyType.CIPHER_KEY, CryptographicAlgorithm.CHACHA20_POLY1305);
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/jagged-framework/src/main/java/com/exceptionfactory/jagged/framework/crypto/CryptographicAlgorithm.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Jagged Contributors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.exceptionfactory.jagged.framework.crypto;
17 |
18 | /**
19 | * Cryptographic Algorithm references
20 | */
21 | enum CryptographicAlgorithm {
22 | /** ChaCha20-Poly1305 Authenticated Encryption with Associated Data algorithm defined in RFC 7539 */
23 | CHACHA20_POLY1305("ChaCha20-Poly1305"),
24 |
25 | /** Keyed-Hash Message Authentication Code with SHA-256 defined in RFC 2104 */
26 | HMACSHA256("HmacSHA256");
27 |
28 | private final String algorithm;
29 |
30 | CryptographicAlgorithm(final String algorithm) {
31 | this.algorithm = algorithm;
32 | }
33 |
34 | /**
35 | * Get algorithm name as defined according to Java Security Standard Names
36 | *
37 | * @return Java Security Standard Name for Cipher Algorithm
38 | */
39 | String getAlgorithm() {
40 | return algorithm;
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/jagged-framework/src/main/java/com/exceptionfactory/jagged/framework/crypto/CryptographicKeyDescription.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Jagged Contributors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.exceptionfactory.jagged.framework.crypto;
17 |
18 | /**
19 | * Abstraction for describing Cryptographic Key properties
20 | */
21 | public interface CryptographicKeyDescription {
22 | /**
23 | * Get key length in bytes
24 | *
25 | * @return Key length in bytes
26 | */
27 | int getKeyLength();
28 | }
29 |
--------------------------------------------------------------------------------
/jagged-framework/src/main/java/com/exceptionfactory/jagged/framework/crypto/CryptographicKeyType.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Jagged Contributors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.exceptionfactory.jagged.framework.crypto;
17 |
18 | /**
19 | * Cryptographic Key Type references for construction and validation
20 | */
21 | enum CryptographicKeyType implements CryptographicKeyDescription {
22 | /** Extracted intermediate key for subsequent expansion */
23 | EXTRACTED_KEY(32),
24 |
25 | /** Encrypted File Key */
26 | ENCRYPTED_FILE_KEY(32),
27 |
28 | /** Header Key */
29 | HEADER_KEY(32),
30 |
31 | /** Cipher Key */
32 | CIPHER_KEY(32),
33 |
34 | /** Payload Nonce */
35 | PAYLOAD_NONCE(16),
36 |
37 | /** Shared Salt Key */
38 | SHARED_SALT(64),
39 |
40 | /** Shared Secret Key */
41 | SHARED_SECRET(32);
42 |
43 | private final int keyLength;
44 |
45 | CryptographicKeyType(final int keyLength) {
46 | this.keyLength = keyLength;
47 | }
48 |
49 | /**
50 | * Get key length in bytes
51 | *
52 | * @return Key length in bytes
53 | */
54 | @Override
55 | public int getKeyLength() {
56 | return keyLength;
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/jagged-framework/src/main/java/com/exceptionfactory/jagged/framework/crypto/EncryptedFileKey.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Jagged Contributors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.exceptionfactory.jagged.framework.crypto;
17 |
18 | /**
19 | * File Key extension of Cryptographic Algorithm Key encrypted with ChaCha20-Poly1305
20 | */
21 | public final class EncryptedFileKey extends CryptographicAlgorithmKey {
22 | /**
23 | * Encrypted File Key constructor with required key byte array
24 | *
25 | * @param key Encrypted Key consisting of 32 bytes
26 | */
27 | public EncryptedFileKey(final byte[] key) {
28 | super(key, CryptographicKeyType.ENCRYPTED_FILE_KEY, CryptographicAlgorithm.CHACHA20_POLY1305);
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/jagged-framework/src/main/java/com/exceptionfactory/jagged/framework/crypto/FileKeyDecryptor.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Jagged Contributors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.exceptionfactory.jagged.framework.crypto;
17 |
18 | import com.exceptionfactory.jagged.FileKey;
19 |
20 | import java.security.GeneralSecurityException;
21 |
22 | /**
23 | * File Key Decryptor abstracts cipher operations for decrypting a File Key
24 | */
25 | public interface FileKeyDecryptor {
26 | /**
27 | * Get File Key from Encrypted File Key
28 | *
29 | * @param encryptedFileKey Encrypted File Key
30 | * @param cipherKey Cipher Key for decrypting File Key
31 | * @return Decrypted File Key
32 | * @throws GeneralSecurityException Thrown on failure of decryption operations
33 | */
34 | FileKey getFileKey(EncryptedFileKey encryptedFileKey, CipherKey cipherKey) throws GeneralSecurityException;
35 | }
36 |
--------------------------------------------------------------------------------
/jagged-framework/src/main/java/com/exceptionfactory/jagged/framework/crypto/FileKeyDecryptorFactory.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Jagged Contributors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.exceptionfactory.jagged.framework.crypto;
17 |
18 | import java.security.Provider;
19 | import java.util.Objects;
20 |
21 | /**
22 | * Factory abstraction for instances of File Key Decryptor
23 | */
24 | public final class FileKeyDecryptorFactory {
25 | private final Provider provider;
26 |
27 | /**
28 | * File Key Decryptor Factory uses the system default Security Provider configuration
29 | */
30 | public FileKeyDecryptorFactory() {
31 | provider = null;
32 | }
33 |
34 | /**
35 | * File Key Decryptor Factory with support for custom Security Provider
36 | *
37 | * @param provider Security Provider supporting ChaCha20-Poly1305
38 | */
39 | public FileKeyDecryptorFactory(final Provider provider) {
40 | this.provider = Objects.requireNonNull(provider, "Provider required");
41 | }
42 |
43 | /**
44 | * Create new instance of File Key Decryptor using current configuration
45 | *
46 | * @return File Key Decryptor
47 | */
48 | public FileKeyDecryptor newFileKeyDecryptor() {
49 | return provider == null ? new StandardFileKeyDecryptor() : new StandardFileKeyDecryptor(provider);
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/jagged-framework/src/main/java/com/exceptionfactory/jagged/framework/crypto/FileKeyEncryptor.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Jagged Contributors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.exceptionfactory.jagged.framework.crypto;
17 |
18 | import com.exceptionfactory.jagged.FileKey;
19 |
20 | import java.security.GeneralSecurityException;
21 |
22 | /**
23 | * File Key Encryptor abstracts cipher operations for encrypting a File Key
24 | */
25 | public interface FileKeyEncryptor {
26 | /**
27 | * Get Encrypted File Key from File Key
28 | *
29 | * @param fileKey File Key
30 | * @param cipherKey Cipher Key for encrypting File Key
31 | * @return Encrypted File Key
32 | * @throws GeneralSecurityException Thrown on failure of encryption operations
33 | */
34 | EncryptedFileKey getEncryptedFileKey(FileKey fileKey, CipherKey cipherKey) throws GeneralSecurityException;
35 | }
36 |
--------------------------------------------------------------------------------
/jagged-framework/src/main/java/com/exceptionfactory/jagged/framework/crypto/FileKeyEncryptorFactory.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Jagged Contributors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.exceptionfactory.jagged.framework.crypto;
17 |
18 | import java.security.Provider;
19 | import java.util.Objects;
20 |
21 | /**
22 | * Factory abstraction for instances of File Key Encryptor
23 | */
24 | public final class FileKeyEncryptorFactory {
25 | private final Provider provider;
26 |
27 | /**
28 | * File Key Encryptor Factory uses the system default Security Provider configuration
29 | */
30 | public FileKeyEncryptorFactory() {
31 | provider = null;
32 | }
33 |
34 | /**
35 | * File Key Encryptor Factory with support for custom Security Provider
36 | *
37 | * @param provider Security Provider supporting ChaCha20-Poly1305
38 | */
39 | public FileKeyEncryptorFactory(final Provider provider) {
40 | this.provider = Objects.requireNonNull(provider, "Provider required");
41 | }
42 |
43 | /**
44 | * Create new instance of File Key Encryptor using current configuration
45 | *
46 | * @return File Key Encryptor
47 | */
48 | public FileKeyEncryptor newFileKeyEncryptor() {
49 | return provider == null ? new StandardFileKeyEncryptor() : new StandardFileKeyEncryptor(provider);
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/jagged-framework/src/main/java/com/exceptionfactory/jagged/framework/crypto/FileKeyIvParameterSpec.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Jagged Contributors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.exceptionfactory.jagged.framework.crypto;
17 |
18 | import javax.crypto.spec.IvParameterSpec;
19 |
20 | /**
21 | * Initialization Vector Parameter Specification for File Key encryption and decryption consisting of 12 zero bytes
22 | */
23 | final class FileKeyIvParameterSpec extends IvParameterSpec {
24 | private static final int INITIALIZATION_VECTOR_LENGTH = 12;
25 |
26 | /**
27 | * File Key Initialization Vector Parameter Specification with array of 12 bytes
28 | */
29 | FileKeyIvParameterSpec() {
30 | super(new byte[INITIALIZATION_VECTOR_LENGTH]);
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/jagged-framework/src/main/java/com/exceptionfactory/jagged/framework/crypto/HeaderKeyProducer.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Jagged Contributors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.exceptionfactory.jagged.framework.crypto;
17 |
18 | import com.exceptionfactory.jagged.FileKey;
19 |
20 | import java.security.GeneralSecurityException;
21 |
22 | /**
23 | * Abstraction for producing Header MAC Key using HMAC-based Extract-and-Expand Key Derivation Function described in RFC 5869
24 | */
25 | public interface HeaderKeyProducer {
26 | /**
27 | * Get derived Header Message Authentication Code Key
28 | *
29 | * @param fileKey File Key
30 | * @return Message Authentication Code Header Key
31 | * @throws GeneralSecurityException Thrown on key derivation failures
32 | */
33 | MacKey getHeaderKey(FileKey fileKey) throws GeneralSecurityException;
34 | }
35 |
--------------------------------------------------------------------------------
/jagged-framework/src/main/java/com/exceptionfactory/jagged/framework/crypto/HeaderKeyProducerFactory.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Jagged Contributors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.exceptionfactory.jagged.framework.crypto;
17 |
18 | /**
19 | * Header Key Producer Factory creates new producers using required arguments
20 | */
21 | public final class HeaderKeyProducerFactory {
22 | private HeaderKeyProducerFactory() {
23 |
24 | }
25 |
26 | /**
27 | * Create a new instance of Header Key Producer
28 | *
29 | * @return Header Key Producer
30 | */
31 | public static HeaderKeyProducer newHeaderKeyProducer() {
32 | return new StandardHeaderKeyProducer();
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/jagged-framework/src/main/java/com/exceptionfactory/jagged/framework/crypto/MacKey.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Jagged Contributors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.exceptionfactory.jagged.framework.crypto;
17 |
18 | /**
19 | * Message Authentication Code Key extension of Cryptographic Algorithm Key using HmacSHA256
20 | */
21 | public class MacKey extends CryptographicAlgorithmKey {
22 | /**
23 | * Message Authentication Code Key constructor with required symmetric key
24 | *
25 | * @param key Symmetric Key with byte length based on Cryptographic Key Type
26 | * @param cryptographicKeyDescription Cryptographic Key Description
27 | */
28 | public MacKey(final byte[] key, final CryptographicKeyDescription cryptographicKeyDescription) {
29 | super(key, cryptographicKeyDescription, CryptographicAlgorithm.HMACSHA256);
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/jagged-framework/src/main/java/com/exceptionfactory/jagged/framework/crypto/MessageAuthenticationCodeProducer.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Jagged Contributors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.exceptionfactory.jagged.framework.crypto;
17 |
18 | import java.nio.ByteBuffer;
19 |
20 | /**
21 | * Producer abstraction for generating a Keyed-Hash Message Authentication Code as described in RFC 2104
22 | */
23 | public interface MessageAuthenticationCodeProducer {
24 | /**
25 | * Get Message Authentication Code using configured Key and provided input bytes
26 | *
27 | * @param inputBuffer Input Buffer from which to produce a Message Authentication Code
28 | * @return Message Authentication Code bytes
29 | */
30 | byte[] getMessageAuthenticationCode(ByteBuffer inputBuffer);
31 | }
32 |
--------------------------------------------------------------------------------
/jagged-framework/src/main/java/com/exceptionfactory/jagged/framework/crypto/MessageAuthenticationCodeProducerFactory.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Jagged Contributors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.exceptionfactory.jagged.framework.crypto;
17 |
18 | import java.security.GeneralSecurityException;
19 |
20 | /**
21 | * Message Authentication Code Producer Factory creates new producers using required arguments
22 | */
23 | public final class MessageAuthenticationCodeProducerFactory {
24 | private MessageAuthenticationCodeProducerFactory() {
25 |
26 | }
27 |
28 | /**
29 | * Create a new instance of Message Authentication Code Producer using MAC Key
30 | *
31 | * @param macKey Message Authentication Code Key required
32 | * @return Message Authentication Code Producer
33 | * @throws GeneralSecurityException Thrown on producer initialization failures
34 | */
35 | public static MessageAuthenticationCodeProducer newMessageAuthenticationCodeProducer(final MacKey macKey) throws GeneralSecurityException {
36 | return new StandardMessageAuthenticationCodeProducer(macKey);
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/jagged-framework/src/main/java/com/exceptionfactory/jagged/framework/crypto/PayloadKeyProducer.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Jagged Contributors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.exceptionfactory.jagged.framework.crypto;
17 |
18 | import com.exceptionfactory.jagged.FileKey;
19 |
20 | import java.security.GeneralSecurityException;
21 |
22 | /**
23 | * Abstraction for producing Payload Key from File Key using HMAC-based Extract-and-Expand Key Derivation Function described in RFC 5869
24 | */
25 | public interface PayloadKeyProducer {
26 | /**
27 | * Get Payload Key
28 | *
29 | * @param fileKey File Key
30 | * @param payloadNonceKey Payload Nonce Key
31 | * @return Payload Cipher Key
32 | * @throws GeneralSecurityException Thrown on key derivation failures
33 | */
34 | CipherKey getPayloadKey(FileKey fileKey, PayloadNonceKey payloadNonceKey) throws GeneralSecurityException;
35 | }
36 |
--------------------------------------------------------------------------------
/jagged-framework/src/main/java/com/exceptionfactory/jagged/framework/crypto/PayloadKeyProducerFactory.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Jagged Contributors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.exceptionfactory.jagged.framework.crypto;
17 |
18 | /**
19 | * Payload Key Producer Factory creates new producers
20 | */
21 | public final class PayloadKeyProducerFactory {
22 | private PayloadKeyProducerFactory() {
23 |
24 | }
25 |
26 | /**
27 | * Create a new Payload Key Producer
28 | *
29 | * @return Payload Key Producer
30 | */
31 | public static PayloadKeyProducer newPayloadKeyProducer() {
32 | return new StandardPayloadKeyProducer();
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/jagged-framework/src/main/java/com/exceptionfactory/jagged/framework/crypto/PayloadNonceKey.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Jagged Contributors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.exceptionfactory.jagged.framework.crypto;
17 |
18 | import java.security.SecureRandom;
19 |
20 | /**
21 | * Payload nonce consisting of 16 bytes from a cryptographically secure pseudorandom number generator
22 | */
23 | public final class PayloadNonceKey extends MacKey {
24 | private static final SecureRandom SECURE_RANDOM = new SecureRandom();
25 |
26 | /**
27 | * Payload nonce key constructor generates a new key using java.util.SecureRandom.nextBytes()
28 | */
29 | public PayloadNonceKey() {
30 | this(getSecureRandomKey());
31 | }
32 |
33 | /**
34 | * Payload nonce key with required byte array
35 | *
36 | * @param key Nonce consisting of 16 bytes
37 | */
38 | public PayloadNonceKey(final byte[] key) {
39 | super(key, CryptographicKeyType.PAYLOAD_NONCE);
40 | }
41 |
42 | private static byte[] getSecureRandomKey() {
43 | final byte[] key = new byte[CryptographicKeyType.PAYLOAD_NONCE.getKeyLength()];
44 | SECURE_RANDOM.nextBytes(key);
45 | return key;
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/jagged-framework/src/main/java/com/exceptionfactory/jagged/framework/crypto/SharedSaltKey.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Jagged Contributors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.exceptionfactory.jagged.framework.crypto;
17 |
18 | /**
19 | * Shared Salt Key extension of Cryptographic Algorithm Key containing the concatenation of shared public keys
20 | */
21 | public final class SharedSaltKey extends MacKey {
22 | /**
23 | * Shared Salt Key constructor with required symmetric key
24 | *
25 | * @param key Symmetric Key consisting of 64 bytes concatenated from shared public keys
26 | */
27 | public SharedSaltKey(final byte[] key) {
28 | super(key, CryptographicKeyType.SHARED_SALT);
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/jagged-framework/src/main/java/com/exceptionfactory/jagged/framework/crypto/SharedSecretKey.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Jagged Contributors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.exceptionfactory.jagged.framework.crypto;
17 |
18 | /**
19 | * Shared Secret Key extension of Cryptographic Algorithm Key containing the results of key agreement processing
20 | */
21 | public final class SharedSecretKey extends MacKey {
22 | /**
23 | * Shared Secret Key constructor with required symmetric key
24 | *
25 | * @param key Symmetric Key consisting of 32 bytes
26 | */
27 | public SharedSecretKey(final byte[] key) {
28 | super(key, CryptographicKeyType.SHARED_SECRET);
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/jagged-framework/src/main/java/com/exceptionfactory/jagged/framework/crypto/StandardMessageAuthenticationCodeProducer.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Jagged Contributors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.exceptionfactory.jagged.framework.crypto;
17 |
18 | import javax.crypto.Mac;
19 | import java.nio.ByteBuffer;
20 | import java.security.GeneralSecurityException;
21 | import java.util.Objects;
22 |
23 | /**
24 | * Standard implementation of Message Authentication Code Producer using javax.crypto.Mac with HMAC-SHA-256
25 | */
26 | final class StandardMessageAuthenticationCodeProducer implements MessageAuthenticationCodeProducer {
27 | private final Mac mac;
28 |
29 | /**
30 | * Standard Message Authentication Code Producer constructor
31 | *
32 | * @param macKey Message Authentication Code Key required
33 | * @throws GeneralSecurityException Thrown on Message Authentication Code initialization failures
34 | */
35 | StandardMessageAuthenticationCodeProducer(final MacKey macKey) throws GeneralSecurityException {
36 | mac = Mac.getInstance(macKey.getAlgorithm());
37 | mac.init(macKey);
38 | }
39 |
40 | /**
41 | * Get Message Authentication Code using configured Key and provided input bytes
42 | *
43 | * @param inputBuffer Input Buffer required
44 | * @return Message Authentication Code bytes derived from HMAC-SHA-256
45 | */
46 | @Override
47 | public byte[] getMessageAuthenticationCode(final ByteBuffer inputBuffer) {
48 | Objects.requireNonNull(inputBuffer, "Input Buffer required");
49 | mac.update(inputBuffer);
50 | return mac.doFinal();
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/jagged-framework/src/main/java/com/exceptionfactory/jagged/framework/crypto/StandardPayloadKeyProducer.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Jagged Contributors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.exceptionfactory.jagged.framework.crypto;
17 |
18 | import com.exceptionfactory.jagged.FileKey;
19 |
20 | import java.security.GeneralSecurityException;
21 | import java.util.Objects;
22 |
23 | /**
24 | * Standard implementation of Payload Key Producer using HMAC-based Extract-and-Expand Key Derivation Function described in RFC 5869
25 | */
26 | class StandardPayloadKeyProducer extends HashedDerivedKeyProducer implements PayloadKeyProducer {
27 | /** Payload Application Information for HKDF-SHA-256 as described in age-encryption Header MAC key derivation */
28 | private static final byte[] PAYLOAD_INFO = new byte[]{'p', 'a', 'y', 'l', 'o', 'a', 'd'};
29 |
30 | /**
31 | * Get Payload Key using HKDF-SHA-256
32 | *
33 | * @param fileKey File Key
34 | * @param payloadNonceKey Payload Nonce Key
35 | * @return Payload Cipher Key
36 | * @throws GeneralSecurityException Thrown on key derivation failures
37 | */
38 | @Override
39 | public CipherKey getPayloadKey(final FileKey fileKey, final PayloadNonceKey payloadNonceKey) throws GeneralSecurityException {
40 | Objects.requireNonNull(fileKey, "File Key required");
41 | Objects.requireNonNull(payloadNonceKey, "Payload Nonce Key required");
42 | final byte[] payloadKey = getDerivedKey(fileKey, payloadNonceKey, PAYLOAD_INFO);
43 | return new CipherKey(payloadKey);
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/jagged-framework/src/main/java/com/exceptionfactory/jagged/framework/format/FileHeader.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Jagged Contributors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.exceptionfactory.jagged.framework.format;
17 |
18 | import com.exceptionfactory.jagged.RecipientStanza;
19 |
20 | /**
21 | * File Header containing Recipient Stanzas and Message Authentication Code from age-encryption header
22 | */
23 | interface FileHeader {
24 | /**
25 | * Get Recipient Stanzas read from File Header
26 | *
27 | * @return Recipient Stanzas
28 | */
29 | Iterable getRecipientStanzas();
30 |
31 | /**
32 | * Get Message Authentication Code bytes
33 | *
34 | * @return Message Authentication Code bytes
35 | */
36 | byte[] getMessageAuthenticationCode();
37 | }
38 |
--------------------------------------------------------------------------------
/jagged-framework/src/main/java/com/exceptionfactory/jagged/framework/format/FileHeaderReader.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Jagged Contributors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.exceptionfactory.jagged.framework.format;
17 |
18 | import java.nio.ByteBuffer;
19 | import java.security.GeneralSecurityException;
20 |
21 | /**
22 | * Abstraction for reading age file header containing one or more Recipient Stanzas
23 | */
24 | interface FileHeaderReader {
25 | /**
26 | * Get File Header with Recipient Stanzas from Channel that starts with standard age header
27 | *
28 | * @param inputBuffer Input Byte Buffer starting with age header
29 | * @return File Header with Recipient Stanzas containing one or more elements
30 | * @throws GeneralSecurityException Thrown on failure to read or process File Header bytes
31 | */
32 | FileHeader getFileHeader(ByteBuffer inputBuffer) throws GeneralSecurityException;
33 | }
34 |
--------------------------------------------------------------------------------
/jagged-framework/src/main/java/com/exceptionfactory/jagged/framework/format/FileHeaderWriter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Jagged Contributors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.exceptionfactory.jagged.framework.format;
17 |
18 | import com.exceptionfactory.jagged.RecipientStanza;
19 |
20 | import java.io.IOException;
21 | import java.nio.ByteBuffer;
22 | import java.security.GeneralSecurityException;
23 |
24 | /**
25 | * File Header Reader serializes Recipient Stanzas according to standard age encryption specifications
26 | */
27 | interface FileHeaderWriter {
28 | /**
29 | * Write Recipient Stanzas along with formatted age header elements
30 | *
31 | * @param recipientStanzas Recipient Stanzas
32 | * @return Byte Buffer containing serialized age header
33 | * @throws GeneralSecurityException Thrown on failures to run cryptographic operations while serializing header
34 | * @throws IOException Thrown on failures to write Recipient Stanzas
35 | */
36 | ByteBuffer writeRecipientStanzas(Iterable recipientStanzas) throws GeneralSecurityException, IOException;
37 | }
38 |
--------------------------------------------------------------------------------
/jagged-framework/src/main/java/com/exceptionfactory/jagged/framework/format/FileKeyReader.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Jagged Contributors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.exceptionfactory.jagged.framework.format;
17 |
18 | import com.exceptionfactory.jagged.FileKey;
19 | import com.exceptionfactory.jagged.RecipientStanzaReader;
20 |
21 | import java.io.IOException;
22 | import java.nio.ByteBuffer;
23 | import java.security.GeneralSecurityException;
24 |
25 | /**
26 | * Abstraction responsible for reading and verifying File Header before returning File Key
27 | */
28 | interface FileKeyReader {
29 | /**
30 | * Read File Key from File Header buffer using provided Recipient Stanza Reader
31 | *
32 | * @param buffer File Header buffer
33 | * @param recipientStanzaReader Recipient Stanza Reader
34 | * @return File Key
35 | * @throws GeneralSecurityException Thrown on failures to read File Key or verify File Header
36 | * @throws IOException Thrown on failures to read File Header
37 | */
38 | FileKey readFileKey(ByteBuffer buffer, RecipientStanzaReader recipientStanzaReader) throws GeneralSecurityException, IOException;
39 | }
40 |
--------------------------------------------------------------------------------
/jagged-framework/src/main/java/com/exceptionfactory/jagged/framework/format/HeaderDecodingException.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Jagged Contributors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.exceptionfactory.jagged.framework.format;
17 |
18 | import java.security.GeneralSecurityException;
19 |
20 | /**
21 | * Header Decoding Exception indicates failures while reading File Header section of age encryption messages
22 | */
23 | class HeaderDecodingException extends GeneralSecurityException {
24 | /**
25 | * Header Decoding Exception with required message indicating problem details
26 | *
27 | * @param message Exception message with problem details
28 | */
29 | HeaderDecodingException(final String message) {
30 | super(message);
31 | }
32 |
33 | /**
34 | * Header Decoding Exception with required message indicating problem details
35 | *
36 | * @param message Exception message with problem details
37 | * @param cause Throwable cause of header failures
38 | */
39 | HeaderDecodingException(final String message, final Throwable cause) {
40 | super(message, cause);
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/jagged-framework/src/main/java/com/exceptionfactory/jagged/framework/format/PayloadKeyReader.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Jagged Contributors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.exceptionfactory.jagged.framework.format;
17 |
18 | import com.exceptionfactory.jagged.RecipientStanzaReader;
19 | import com.exceptionfactory.jagged.framework.crypto.CipherKey;
20 |
21 | import java.io.IOException;
22 | import java.nio.ByteBuffer;
23 | import java.security.GeneralSecurityException;
24 |
25 | /**
26 | * Abstraction responsible for reading File Header and deriving Payload Key from File Key after header verification
27 | */
28 | public interface PayloadKeyReader {
29 | /**
30 | * Get Payload Key from File Header buffer using provided Recipient Stanza Readers to read File Key
31 | *
32 | * @param buffer File Header buffer
33 | * @param recipientStanzaReaders Recipient Stanza Readers
34 | * @return Payload Key
35 | * @throws GeneralSecurityException Thrown on failures to derive Payload Key
36 | * @throws IOException Thrown on failures to read File Header
37 | */
38 | CipherKey getPayloadKey(ByteBuffer buffer, Iterable recipientStanzaReaders) throws GeneralSecurityException, IOException;
39 | }
40 |
--------------------------------------------------------------------------------
/jagged-framework/src/main/java/com/exceptionfactory/jagged/framework/format/PayloadKeyWriter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Jagged Contributors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.exceptionfactory.jagged.framework.format;
17 |
18 | import com.exceptionfactory.jagged.RecipientStanzaWriter;
19 | import com.exceptionfactory.jagged.framework.crypto.CipherKey;
20 |
21 | import java.io.IOException;
22 | import java.nio.ByteBuffer;
23 | import java.security.GeneralSecurityException;
24 |
25 | /**
26 | * Abstraction responsible for writing File Header and returning a Payload Key from a generated File Key
27 | */
28 | public interface PayloadKeyWriter {
29 | /**
30 | * Write File Header to buffer after generating a File Key and return derived Payload Key
31 | *
32 | * @param buffer Byte Buffer with sufficient capacity for serialized File Header should support at least 128 bytes
33 | * @param recipientStanzaWriters Recipient Stanza Writers
34 | * @return Derived Payload Cipher Key for encryption operations
35 | * @throws GeneralSecurityException Thrown on cipher operation failures
36 | * @throws IOException Thrown on serialization failures
37 | */
38 | CipherKey writeFileHeader(ByteBuffer buffer, Iterable recipientStanzaWriters) throws GeneralSecurityException, IOException;
39 | }
40 |
--------------------------------------------------------------------------------
/jagged-framework/src/main/java/com/exceptionfactory/jagged/framework/format/SectionIndicator.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Jagged Contributors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.exceptionfactory.jagged.framework.format;
17 |
18 | import java.nio.charset.StandardCharsets;
19 |
20 | /**
21 | * age-encryption Section Indicator for File Header as described in ABNF definitions
22 | */
23 | enum SectionIndicator {
24 | /** First line with Version 1 */
25 | VERSION("age-encryption.org/v1"),
26 |
27 | /** Stanza Line indicator */
28 | STANZA("-> "),
29 |
30 | /** End of header indicator */
31 | END("---");
32 |
33 | private final byte[] indicator;
34 |
35 | SectionIndicator(final String indicator) {
36 | this.indicator = indicator.getBytes(StandardCharsets.UTF_8);
37 | }
38 |
39 | byte[] getIndicator() {
40 | return indicator;
41 | }
42 |
43 | int getLength() {
44 | return indicator.length;
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/jagged-framework/src/main/java/com/exceptionfactory/jagged/framework/format/SectionSeparator.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Jagged Contributors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.exceptionfactory.jagged.framework.format;
17 |
18 | /**
19 | * age-encryption Section Separator for File Header elements
20 | */
21 | enum SectionSeparator {
22 | /** Line Feed Character */
23 | LINE_FEED(10),
24 |
25 | /** Space Character */
26 | SPACE(32);
27 |
28 | private final int code;
29 |
30 | SectionSeparator(final int code) {
31 | this.code = code;
32 | }
33 |
34 | int getCode() {
35 | return code;
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/jagged-framework/src/main/java/com/exceptionfactory/jagged/framework/format/StandardFileHeader.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Jagged Contributors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.exceptionfactory.jagged.framework.format;
17 |
18 | import com.exceptionfactory.jagged.RecipientStanza;
19 |
20 | import java.util.Objects;
21 |
22 | /**
23 | * Standard implementation of age-encryption File Header
24 | */
25 | class StandardFileHeader implements FileHeader {
26 | private final Iterable recipientStanzas;
27 |
28 | private final byte[] messageAuthenticationCode;
29 |
30 | StandardFileHeader(final Iterable recipientStanzas, final byte[] messageAuthenticationCode) {
31 | this.recipientStanzas = Objects.requireNonNull(recipientStanzas, "Recipient Stanzas required");
32 | this.messageAuthenticationCode = Objects.requireNonNull(messageAuthenticationCode, "Message Authentication Code required");
33 | }
34 |
35 | @Override
36 | public Iterable getRecipientStanzas() {
37 | return recipientStanzas;
38 | }
39 |
40 | @Override
41 | public byte[] getMessageAuthenticationCode() {
42 | return messageAuthenticationCode.clone();
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/jagged-framework/src/main/java/com/exceptionfactory/jagged/framework/format/StandardRecipientStanza.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Jagged Contributors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.exceptionfactory.jagged.framework.format;
17 |
18 | import com.exceptionfactory.jagged.RecipientStanza;
19 |
20 | import java.util.Collections;
21 | import java.util.List;
22 | import java.util.Objects;
23 |
24 | /**
25 | * Standard implementation of Recipient Stanza
26 | */
27 | class StandardRecipientStanza implements RecipientStanza {
28 | private final String type;
29 |
30 | private final List arguments;
31 |
32 | private final byte[] body;
33 |
34 | StandardRecipientStanza(final String type, final List arguments, final byte[] body) {
35 | this.type = Objects.requireNonNull(type, "Type required");
36 | this.arguments = Collections.unmodifiableList(Objects.requireNonNull(arguments, "Arguments required"));
37 | this.body = Objects.requireNonNull(body, "Body required");
38 | }
39 |
40 | @Override
41 | public String getType() {
42 | return type;
43 | }
44 |
45 | @Override
46 | public List getArguments() {
47 | return arguments;
48 | }
49 |
50 | @Override
51 | public byte[] getBody() {
52 | return body.clone();
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/jagged-framework/src/main/java/com/exceptionfactory/jagged/framework/stream/ChunkSize.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Jagged Contributors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.exceptionfactory.jagged.framework.stream;
17 |
18 | /**
19 | * STREAM Chunk Size definitions according to age-encryption Payload section
20 | */
21 | enum ChunkSize {
22 | /** Encrypted chunk size including ChaCha20-Poly1305 tag */
23 | ENCRYPTED(65552),
24 |
25 | /** Plain chunk size before encryption and after decryption */
26 | PLAIN(65536);
27 |
28 | private final int size;
29 |
30 | ChunkSize(final int size) {
31 | this.size = size;
32 | }
33 |
34 | /**
35 | * Get chunk size in bytes
36 | *
37 | * @return Chunk size in bytes
38 | */
39 | public int getSize() {
40 | return size;
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/jagged-framework/src/test/java/com/exceptionfactory/jagged/framework/codec/CanonicalBase64DecoderTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Jagged Contributors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.exceptionfactory.jagged.framework.codec;
17 |
18 | import org.junit.jupiter.api.Test;
19 |
20 | import java.nio.charset.StandardCharsets;
21 |
22 | import static org.junit.jupiter.api.Assertions.assertArrayEquals;
23 | import static org.junit.jupiter.api.Assertions.assertThrows;
24 |
25 | class CanonicalBase64DecoderTest {
26 | private static final byte[] DECODED = new byte[]{1};
27 |
28 | private static final String ENCODED_WITH_PADDING = "AQ==";
29 |
30 | private static final String ENCODED_WITHOUT_PADDING = "AQ";
31 |
32 | private static final byte[] ENCODED_BYTES_WITHOUT_PADDING = ENCODED_WITHOUT_PADDING.getBytes(StandardCharsets.ISO_8859_1);
33 |
34 | private static final byte[] ENCODED_BYTE_WITH_PADDING = ENCODED_WITH_PADDING.getBytes(StandardCharsets.ISO_8859_1);
35 |
36 | @Test
37 | void testDecode() {
38 | final CanonicalBase64Decoder decoder = new CanonicalBase64Decoder();
39 |
40 | final byte[] decoded = decoder.decode(ENCODED_BYTES_WITHOUT_PADDING);
41 |
42 | assertArrayEquals(DECODED, decoded);
43 | }
44 |
45 | @Test
46 | void testDecodeWithPadding() {
47 | final CanonicalBase64Decoder decoder = new CanonicalBase64Decoder();
48 |
49 | assertThrows(IllegalArgumentException.class, () -> decoder.decode(ENCODED_BYTE_WITH_PADDING));
50 | }
51 |
52 | @Test
53 | void testDecodeNull() {
54 | final CanonicalBase64Decoder decoder = new CanonicalBase64Decoder();
55 |
56 | assertThrows(IllegalArgumentException.class, () -> decoder.decode(null));
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/jagged-framework/src/test/java/com/exceptionfactory/jagged/framework/codec/CanonicalBase64EncoderTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Jagged Contributors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.exceptionfactory.jagged.framework.codec;
17 |
18 | import org.junit.jupiter.api.Test;
19 |
20 | import java.nio.charset.StandardCharsets;
21 |
22 | import static org.junit.jupiter.api.Assertions.assertArrayEquals;
23 | import static org.junit.jupiter.api.Assertions.assertEquals;
24 |
25 | class CanonicalBase64EncoderTest {
26 | private static final byte[] SOURCE = new byte[]{1};
27 |
28 | private static final String ENCODED_WITHOUT_PADDING = "AQ";
29 |
30 | private static final byte[] ENCODED_BYTES_WITHOUT_PADDING = ENCODED_WITHOUT_PADDING.getBytes(StandardCharsets.ISO_8859_1);
31 |
32 | @Test
33 | void testEncodeToString() {
34 | final CanonicalBase64Encoder encoder = new CanonicalBase64Encoder();
35 |
36 | final String encoded = encoder.encodeToString(SOURCE);
37 |
38 | assertEquals(ENCODED_WITHOUT_PADDING, encoded);
39 | }
40 |
41 | @Test
42 | void testEncode() {
43 | final CanonicalBase64Encoder encoder = new CanonicalBase64Encoder();
44 |
45 | final byte[] encoded = encoder.encode(SOURCE);
46 |
47 | assertArrayEquals(ENCODED_BYTES_WITHOUT_PADDING, encoded);
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/jagged-framework/src/test/java/com/exceptionfactory/jagged/framework/crypto/FileKeyIvParameterSpecTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Jagged Contributors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.exceptionfactory.jagged.framework.crypto;
17 |
18 | import org.junit.jupiter.api.Test;
19 |
20 | import static org.junit.jupiter.api.Assertions.assertArrayEquals;
21 |
22 | class FileKeyIvParameterSpecTest {
23 | private static final int INITIALIZATION_VECTOR_LENGTH = 12;
24 |
25 | private static final byte[] EMPTY_INITIALIZATION_VECTOR = new byte[INITIALIZATION_VECTOR_LENGTH];
26 |
27 | @Test
28 | void testParameterSpec() {
29 | final FileKeyIvParameterSpec parameterSpec = new FileKeyIvParameterSpec();
30 |
31 | final byte[] initializationVector = parameterSpec.getIV();
32 |
33 | assertArrayEquals(EMPTY_INITIALIZATION_VECTOR, initializationVector);
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/jagged-framework/src/test/java/com/exceptionfactory/jagged/framework/crypto/HeaderKeyProducerFactoryTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Jagged Contributors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.exceptionfactory.jagged.framework.crypto;
17 |
18 | import org.junit.jupiter.api.Test;
19 |
20 | import static org.junit.jupiter.api.Assertions.assertNotNull;
21 |
22 | class HeaderKeyProducerFactoryTest {
23 |
24 | @Test
25 | void testNewHeaderKeyProducer() {
26 | final HeaderKeyProducer headerKeyProducer = HeaderKeyProducerFactory.newHeaderKeyProducer();
27 |
28 | assertNotNull(headerKeyProducer);
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/jagged-framework/src/test/java/com/exceptionfactory/jagged/framework/crypto/MacKeyTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Jagged Contributors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.exceptionfactory.jagged.framework.crypto;
17 |
18 | import org.junit.jupiter.api.Test;
19 |
20 | import static org.junit.jupiter.api.Assertions.assertArrayEquals;
21 | import static org.junit.jupiter.api.Assertions.assertEquals;
22 | import static org.junit.jupiter.api.Assertions.assertThrows;
23 |
24 | class MacKeyTest {
25 | static final byte[] SYMMETRIC_KEY = new byte[]{
26 | 1, 2, 3, 4, 5, 6, 7, 8,
27 | 1, 2, 3, 4, 5, 6, 7, 8,
28 | 1, 2, 3, 4, 5, 6, 7, 8,
29 | 1, 2, 3, 4, 5, 6, 7, 8
30 | };
31 |
32 | private static final byte[] INVALID_KEY = new byte[0];
33 |
34 | @Test
35 | void testMacKey() {
36 | final MacKey macKey = new MacKey(SYMMETRIC_KEY, CryptographicKeyType.EXTRACTED_KEY);
37 |
38 | assertEquals(CryptographicAlgorithm.HMACSHA256.getAlgorithm(), macKey.getAlgorithm());
39 | assertArrayEquals(SYMMETRIC_KEY, macKey.getEncoded());
40 | }
41 |
42 | @Test
43 | void testMacKeyLengthNotValid() {
44 | assertThrows(IllegalArgumentException.class, () -> new MacKey(INVALID_KEY, CryptographicKeyType.HEADER_KEY));
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/jagged-framework/src/test/java/com/exceptionfactory/jagged/framework/crypto/MessageAuthenticationCodeProducerFactoryTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Jagged Contributors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.exceptionfactory.jagged.framework.crypto;
17 |
18 | import org.junit.jupiter.api.Test;
19 |
20 | import java.security.GeneralSecurityException;
21 |
22 | import static org.junit.jupiter.api.Assertions.assertNotNull;
23 |
24 | class MessageAuthenticationCodeProducerFactoryTest {
25 |
26 | @Test
27 | void testNewByteBufferDecryptor() throws GeneralSecurityException {
28 | final MacKey macKey = new MacKey(MacKeyTest.SYMMETRIC_KEY, CryptographicKeyType.EXTRACTED_KEY);
29 |
30 | final MessageAuthenticationCodeProducer messageAuthenticationCodeProducer = MessageAuthenticationCodeProducerFactory.newMessageAuthenticationCodeProducer(macKey);
31 |
32 | assertNotNull(messageAuthenticationCodeProducer);
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/jagged-framework/src/test/java/com/exceptionfactory/jagged/framework/crypto/PayloadKeyProducerFactoryTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Jagged Contributors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.exceptionfactory.jagged.framework.crypto;
17 |
18 | import org.junit.jupiter.api.Test;
19 |
20 | import static org.junit.jupiter.api.Assertions.assertNotNull;
21 |
22 | class PayloadKeyProducerFactoryTest {
23 |
24 | @Test
25 | void testNewPayloadKeyProducer() {
26 | final PayloadKeyProducer payloadKeyProducer = PayloadKeyProducerFactory.newPayloadKeyProducer();
27 |
28 | assertNotNull(payloadKeyProducer);
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/jagged-framework/src/test/java/com/exceptionfactory/jagged/framework/crypto/SharedSaltKeyTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Jagged Contributors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.exceptionfactory.jagged.framework.crypto;
17 |
18 | import org.junit.jupiter.api.Test;
19 |
20 | import static org.junit.jupiter.api.Assertions.assertArrayEquals;
21 | import static org.junit.jupiter.api.Assertions.assertEquals;
22 | import static org.junit.jupiter.api.Assertions.assertThrows;
23 |
24 | class SharedSaltKeyTest {
25 | private static final byte[] INVALID_KEY = new byte[0];
26 |
27 | @Test
28 | void testSharedSaltKey() {
29 | final byte[] encoded = new byte[CryptographicKeyType.SHARED_SALT.getKeyLength()];
30 | final SharedSaltKey sharedSaltKey = new SharedSaltKey(encoded);
31 |
32 | assertEquals(CryptographicAlgorithm.HMACSHA256.getAlgorithm(), sharedSaltKey.getAlgorithm());
33 | assertArrayEquals(encoded, sharedSaltKey.getEncoded());
34 | }
35 |
36 | @Test
37 | void testSharedSaltKeyLengthNotValid() {
38 | assertThrows(IllegalArgumentException.class, () -> new SharedSaltKey(INVALID_KEY));
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/jagged-framework/src/test/java/com/exceptionfactory/jagged/framework/crypto/SharedSecretKeyTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Jagged Contributors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.exceptionfactory.jagged.framework.crypto;
17 |
18 | import org.junit.jupiter.api.Test;
19 |
20 | import static org.junit.jupiter.api.Assertions.assertArrayEquals;
21 | import static org.junit.jupiter.api.Assertions.assertEquals;
22 | import static org.junit.jupiter.api.Assertions.assertThrows;
23 |
24 | class SharedSecretKeyTest {
25 | private static final byte[] INVALID_KEY = new byte[0];
26 |
27 | @Test
28 | void testSharedSecretKey() {
29 | final byte[] encoded = new byte[CryptographicKeyType.SHARED_SECRET.getKeyLength()];
30 | final SharedSecretKey sharedSecretKey = new SharedSecretKey(encoded);
31 |
32 | assertEquals(CryptographicAlgorithm.HMACSHA256.getAlgorithm(), sharedSecretKey.getAlgorithm());
33 | assertArrayEquals(encoded, sharedSecretKey.getEncoded());
34 | }
35 |
36 | @Test
37 | void testSharedSecretKeyLengthNotValid() {
38 | assertThrows(IllegalArgumentException.class, () -> new SharedSecretKey(INVALID_KEY));
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/jagged-framework/src/test/java/com/exceptionfactory/jagged/framework/crypto/StandardByteBufferEncryptorTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Jagged Contributors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.exceptionfactory.jagged.framework.crypto;
17 |
18 | import org.junit.jupiter.api.Test;
19 |
20 | import javax.crypto.spec.IvParameterSpec;
21 | import java.nio.ByteBuffer;
22 | import java.security.GeneralSecurityException;
23 |
24 | import static org.junit.jupiter.api.Assertions.assertArrayEquals;
25 | import static org.junit.jupiter.api.Assertions.assertEquals;
26 |
27 | class StandardByteBufferEncryptorTest {
28 | static final byte[] INPUT = new byte[]{0, 1, 2, 3};
29 |
30 | static final byte[] EXPECTED_OUTPUT = new byte[]{75, -23, -98, 103, 100, 11, 71, 7, 38, 115, -38, -46, 11, -73, 78, -45, 13, -4, -82, -6};
31 |
32 | @Test
33 | void testEncrypt() throws GeneralSecurityException {
34 | final CipherKey cipherKey = new CipherKey(CipherKeyTest.SYMMETRIC_KEY);
35 | final IvParameterSpec parameterSpec = new IvParameterSpec(CipherFactoryTest.INITIALIZATION_VECTOR);
36 |
37 | final CipherFactory cipherFactory = new CipherFactory();
38 | final StandardByteBufferEncryptor encryptor = new StandardByteBufferEncryptor(cipherFactory, cipherKey, parameterSpec);
39 |
40 | final ByteBuffer inputBuffer = ByteBuffer.wrap(INPUT);
41 | final ByteBuffer outputBuffer = ByteBuffer.allocate(EXPECTED_OUTPUT.length);
42 |
43 | final int encryptedLength = encryptor.encrypt(inputBuffer, outputBuffer);
44 |
45 | assertEquals(EXPECTED_OUTPUT.length, encryptedLength);
46 | final byte[] output = outputBuffer.array();
47 | assertArrayEquals(EXPECTED_OUTPUT, output);
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/jagged-framework/src/test/java/com/exceptionfactory/jagged/framework/crypto/StandardHeaderKeyProducerTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Jagged Contributors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.exceptionfactory.jagged.framework.crypto;
17 |
18 | import com.exceptionfactory.jagged.FileKey;
19 | import org.junit.jupiter.api.Test;
20 |
21 | import java.security.GeneralSecurityException;
22 |
23 | import static org.junit.jupiter.api.Assertions.assertArrayEquals;
24 | import static org.junit.jupiter.api.Assertions.assertNotNull;
25 |
26 | class StandardHeaderKeyProducerTest {
27 | static final byte[] FILE_KEY = new byte[]{
28 | 1, 2, 3, 4, 5, 6, 7, 8,
29 | 1, 2, 3, 4, 5, 6, 7, 8
30 | };
31 |
32 | static final byte[] HEADER_KEY = new byte[]{
33 | 50, 103, -85, -117, 80, 49, -69, -100,
34 | 36, -42, 85, 10, -66, -104, 100, 80,
35 | 90, 31, -92, -51, 54, -3, -4, -83,
36 | 8, -114, -5, 52, 124, -41, 52, 28
37 | };
38 |
39 | @Test
40 | void testGetHeaderKey() throws GeneralSecurityException {
41 | final FileKey fileKey = new FileKey(FILE_KEY);
42 |
43 | final StandardHeaderKeyProducer producer = new StandardHeaderKeyProducer();
44 |
45 | final MacKey headerKey = producer.getHeaderKey(fileKey);
46 |
47 | assertNotNull(headerKey);
48 | assertArrayEquals(HEADER_KEY, headerKey.getEncoded());
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/jagged-framework/src/test/java/com/exceptionfactory/jagged/framework/crypto/StandardMessageAuthenticationCodeProducerTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Jagged Contributors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.exceptionfactory.jagged.framework.crypto;
17 |
18 | import org.junit.jupiter.api.Test;
19 |
20 | import java.nio.ByteBuffer;
21 | import java.security.GeneralSecurityException;
22 |
23 | import static org.junit.jupiter.api.Assertions.assertArrayEquals;
24 |
25 | class StandardMessageAuthenticationCodeProducerTest {
26 | static final byte[] INPUT = new byte[]{0, 1, 2, 3};
27 |
28 | static final byte[] EXPECTED_OUTPUT = new byte[]{
29 | -70, 108, -59, 94, 32, 29, 24, 57,
30 | 18, -109, -115, 55, -64, -37, 70, -112,
31 | -16, 5, -115, -73, 109, 76, -4, 51,
32 | -39, -103, 92, 17, -30, -26, -10, -70
33 | };
34 |
35 | @Test
36 | void testGetMessageAuthenticationCode() throws GeneralSecurityException {
37 | final MacKey macKey = new MacKey(MacKeyTest.SYMMETRIC_KEY, CryptographicKeyType.EXTRACTED_KEY);
38 | final StandardMessageAuthenticationCodeProducer producer = new StandardMessageAuthenticationCodeProducer(macKey);
39 |
40 | final ByteBuffer inputBuffer = ByteBuffer.wrap(INPUT);
41 | final byte[] messageAuthenticationCode = producer.getMessageAuthenticationCode(inputBuffer);
42 |
43 | assertArrayEquals(EXPECTED_OUTPUT, messageAuthenticationCode);
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/jagged-scrypt/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 |
8 | com.exceptionfactory.jagged
9 | jagged
10 | 1.0.1-SNAPSHOT
11 |
12 |
13 | jagged-scrypt
14 | jagged-scrypt
15 | Jagged scrypt recipient support for age encryption
16 | https://github.com/exceptionfactory/jagged
17 |
18 |
19 |
20 | com.exceptionfactory.jagged
21 | jagged-api
22 |
23 |
24 | com.exceptionfactory.jagged
25 | jagged-framework
26 |
27 |
28 | org.junit.jupiter
29 | junit-jupiter-api
30 | test
31 |
32 |
33 | org.mockito
34 | mockito-core
35 | test
36 |
37 |
38 | org.mockito
39 | mockito-junit-jupiter
40 | test
41 |
42 |
43 |
44 |
45 |
46 |
47 | org.apache.maven.plugins
48 | maven-jar-plugin
49 |
50 |
51 |
52 | ${project.groupId}.scrypt
53 |
54 |
55 |
56 |
57 |
58 |
59 |
--------------------------------------------------------------------------------
/jagged-scrypt/src/main/java/com/exceptionfactory/jagged/scrypt/DerivedWrapKeyProducer.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Jagged Contributors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.exceptionfactory.jagged.scrypt;
17 |
18 | import com.exceptionfactory.jagged.framework.crypto.CipherKey;
19 |
20 | import java.security.GeneralSecurityException;
21 |
22 | /**
23 | * Abstraction for producing Wrap Key derived from scrypt parameters
24 | */
25 | interface DerivedWrapKeyProducer {
26 | /**
27 | * Get Wrap Key
28 | *
29 | * @param salt Salt array of 16 bytes to derive scrypt S salt parameter
30 | * @param workFactor Work factor to derive scrypt N cost parameter
31 | * @return Recipient Stanza Cipher Key for decrypting File Key
32 | * @throws GeneralSecurityException Thrown on key derivation failures
33 | */
34 | CipherKey getWrapKey(byte[] salt, int workFactor) throws GeneralSecurityException;
35 | }
36 |
--------------------------------------------------------------------------------
/jagged-scrypt/src/main/java/com/exceptionfactory/jagged/scrypt/RecipientIndicator.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Jagged Contributors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.exceptionfactory.jagged.scrypt;
17 |
18 | /**
19 | * scrypt Recipient Indicators for reading and writing Recipient Stanzas
20 | */
21 | enum RecipientIndicator {
22 | /** Recipient Stanza Type */
23 | STANZA_TYPE("scrypt"),
24 |
25 | /** Label prepended to random salt for scrypt function */
26 | SALT_LABEL("age-encryption.org/v1/scrypt");
27 |
28 | private final String indicator;
29 |
30 | RecipientIndicator(final String indicator) {
31 | this.indicator = indicator;
32 | }
33 |
34 | public String getIndicator() {
35 | return indicator;
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/jagged-scrypt/src/test/java/com/exceptionfactory/jagged/scrypt/PasswordBasedKeyDerivationFunction2Test.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Jagged Contributors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.exceptionfactory.jagged.scrypt;
17 |
18 | import org.junit.jupiter.api.Test;
19 |
20 | import java.nio.charset.Charset;
21 | import java.nio.charset.StandardCharsets;
22 | import java.security.GeneralSecurityException;
23 |
24 | import static org.junit.jupiter.api.Assertions.assertArrayEquals;
25 |
26 | class PasswordBasedKeyDerivationFunction2Test {
27 | private static final Charset CHARACTER_SET = StandardCharsets.US_ASCII;
28 |
29 | private static final String PASSPHRASE = "passwd";
30 |
31 | private static final String SALT = "salt";
32 |
33 | private static final int DERIVED_KEY_LENGTH = 64;
34 |
35 | /** RFC 7914 Section 11 Input Test Vector for PBKDF2-HMAC-SHA-256 */
36 | private static final String[] SINGLE_ITERATION_VECTOR = new String[]{
37 | "55 ac 04 6e 56 e3 08 9f ec 16 91 c2 25 44 b6 05",
38 | "f9 41 85 21 6d de 04 65 e6 8b 9d 57 c2 0d ac bc",
39 | "49 ca 9c cc f1 79 b6 45 99 16 64 b3 9d 77 ef 31",
40 | "7c 71 b8 45 b1 e3 0b d5 09 11 20 41 d3 a1 97 83"
41 | };
42 |
43 | @Test
44 | void testVector() throws GeneralSecurityException {
45 | final byte[] outputVector = ScryptFunctionTest.getOutputVector(SINGLE_ITERATION_VECTOR);
46 |
47 | final byte[] password = PASSPHRASE.getBytes(CHARACTER_SET);
48 | final byte[] salt = SALT.getBytes(CHARACTER_SET);
49 | final byte[] derivedKey = PasswordBasedKeyDerivationFunction2.getDerivedKey(password, salt, DERIVED_KEY_LENGTH);
50 |
51 | assertArrayEquals(outputVector, derivedKey);
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/jagged-scrypt/src/test/java/com/exceptionfactory/jagged/scrypt/ScryptDerivedWrapKeyProducerTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Jagged Contributors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.exceptionfactory.jagged.scrypt;
17 |
18 | import com.exceptionfactory.jagged.framework.crypto.CipherKey;
19 | import org.junit.jupiter.api.BeforeEach;
20 | import org.junit.jupiter.api.Test;
21 |
22 | import java.nio.charset.StandardCharsets;
23 | import java.security.GeneralSecurityException;
24 |
25 | import static org.junit.jupiter.api.Assertions.assertNotNull;
26 |
27 | class ScryptDerivedWrapKeyProducerTest {
28 | private static final byte[] PASSPHRASE = String.class.getName().getBytes(StandardCharsets.UTF_8);
29 |
30 | private static final byte[] EMPTY_SALT = new byte[]{};
31 |
32 | private static final int MINIMUM_WORK_FACTOR = 2;
33 |
34 | private ScryptDerivedWrapKeyProducer producer;
35 |
36 | @BeforeEach
37 | void setProducer() {
38 | producer = new ScryptDerivedWrapKeyProducer(PASSPHRASE);
39 | }
40 |
41 | @Test
42 | void testGetWrapKey() throws GeneralSecurityException {
43 | final CipherKey wrapKey = producer.getWrapKey(EMPTY_SALT, MINIMUM_WORK_FACTOR);
44 |
45 | assertNotNull(wrapKey);
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/jagged-scrypt/src/test/java/com/exceptionfactory/jagged/scrypt/ScryptRecipientStanzaWriterFactoryTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Jagged Contributors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.exceptionfactory.jagged.scrypt;
17 |
18 | import com.exceptionfactory.jagged.RecipientStanzaWriter;
19 | import org.junit.jupiter.api.Test;
20 |
21 | import java.nio.charset.StandardCharsets;
22 | import java.security.Provider;
23 | import java.security.Security;
24 |
25 | import static org.junit.jupiter.api.Assertions.assertNotNull;
26 |
27 | class ScryptRecipientStanzaWriterFactoryTest {
28 | private static final String ALGORITHM_FILTER = "Cipher.ChaCha20-Poly1305";
29 |
30 | private static final byte[] PASSPHRASE = String.class.getName().getBytes(StandardCharsets.UTF_8);
31 |
32 | private static final int WORK_FACTOR = 14;
33 |
34 | @Test
35 | void testNewRecipientStanzaWriter() {
36 | final RecipientStanzaWriter recipientStanzaWriter = ScryptRecipientStanzaWriterFactory.newRecipientStanzaWriter(PASSPHRASE, WORK_FACTOR);
37 |
38 | assertNotNull(recipientStanzaWriter);
39 | }
40 |
41 | @Test
42 | void testNewRecipientStanzaWriterWithProvider() {
43 | final Provider provider = getProvider();
44 | final RecipientStanzaWriter recipientStanzaWriter = ScryptRecipientStanzaWriterFactory.newRecipientStanzaWriter(PASSPHRASE, WORK_FACTOR, provider);
45 |
46 | assertNotNull(recipientStanzaWriter);
47 | }
48 |
49 | private Provider getProvider() {
50 | final Provider[] providers = Security.getProviders(ALGORITHM_FILTER);
51 | return providers[0];
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/jagged-ssh/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 |
8 | com.exceptionfactory.jagged
9 | jagged
10 | 1.0.1-SNAPSHOT
11 |
12 |
13 | jagged-ssh
14 | jagged-ssh
15 | Jagged SSH recipient support for age encryption
16 | https://github.com/exceptionfactory/jagged
17 |
18 |
19 |
20 | com.exceptionfactory.jagged
21 | jagged-api
22 |
23 |
24 | com.exceptionfactory.jagged
25 | jagged-framework
26 |
27 |
28 | org.junit.jupiter
29 | junit-jupiter-api
30 | test
31 |
32 |
33 | org.mockito
34 | mockito-core
35 | test
36 |
37 |
38 | org.mockito
39 | mockito-junit-jupiter
40 | test
41 |
42 |
43 |
44 |
45 |
46 |
47 | org.apache.maven.plugins
48 | maven-jar-plugin
49 |
50 |
51 |
52 | ${project.groupId}.ssh
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
--------------------------------------------------------------------------------
/jagged-ssh/src/main/java/com/exceptionfactory/jagged/ssh/Ed25519KeyIndicator.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Jagged Contributors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.exceptionfactory.jagged.ssh;
17 |
18 | /**
19 | * Ed25519 Key indicator fields
20 | */
21 | enum Ed25519KeyIndicator {
22 | /** Algorithm */
23 | KEY_ALGORITHM("Ed25519"),
24 |
25 | /** Format */
26 | KEY_FORMAT("RAW");
27 |
28 | private final String indicator;
29 |
30 | Ed25519KeyIndicator(final String indicator) {
31 | this.indicator = indicator;
32 | }
33 |
34 | String getIndicator() {
35 | return indicator;
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/jagged-ssh/src/main/java/com/exceptionfactory/jagged/ssh/Ed25519PublicKey.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Jagged Contributors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.exceptionfactory.jagged.ssh;
17 |
18 | import java.security.PublicKey;
19 | import java.util.Objects;
20 |
21 | /**
22 | * Ed25519 Public Key containing raw key bytes
23 | */
24 | class Ed25519PublicKey implements PublicKey {
25 | private final byte[] encoded;
26 |
27 | /**
28 | * Ed25519 Public Key constructor with raw key bytes
29 | *
30 | * @param encoded raw byte array of 32 bytes
31 | */
32 | Ed25519PublicKey(final byte[] encoded) {
33 | this.encoded = Objects.requireNonNull(encoded, "Encoded Key required");
34 | }
35 |
36 | /**
37 | * Get algorithm describes the type of key
38 | *
39 | * @return Algorithm is Ed25519
40 | */
41 | @Override
42 | public String getAlgorithm() {
43 | return Ed25519KeyIndicator.KEY_ALGORITHM.getIndicator();
44 | }
45 |
46 | /**
47 | * Get format describes the encoded content bytes
48 | *
49 | * @return Encoded key format is RAW
50 | */
51 | @Override
52 | public String getFormat() {
53 | return Ed25519KeyIndicator.KEY_FORMAT.getIndicator();
54 | }
55 |
56 | /**
57 | * Get encoded key bytes consisting of original key
58 | *
59 | * @return encoded public key bytes
60 | */
61 | @Override
62 | public byte[] getEncoded() {
63 | return encoded.clone();
64 | }
65 |
66 | /**
67 | * Get string representation of key algorithm
68 | *
69 | * @return Key algorithm
70 | */
71 | @Override
72 | public String toString() {
73 | return getAlgorithm();
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/jagged-ssh/src/main/java/com/exceptionfactory/jagged/ssh/EllipticCurveKeyType.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Jagged Contributors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.exceptionfactory.jagged.ssh;
17 |
18 | /**
19 | * Elliptic Curve Key Type enumerates standard properties for Ed25519 and X25519 keys
20 | */
21 | enum EllipticCurveKeyType {
22 | /** Ed25519 coordinate key of 32 bytes for twisted Edwards curve digital signature operations */
23 | ED25519("Ed25519", 32),
24 |
25 | /** Curve25519 coordinate key of 32 bytes for X25519 key agreement operations */
26 | X25519("X25519", 32);
27 |
28 | private final String algorithm;
29 |
30 | private final int keyLength;
31 |
32 | EllipticCurveKeyType(final String algorithm, final int keyLength) {
33 | this.algorithm = algorithm;
34 | this.keyLength = keyLength;
35 | }
36 |
37 | /**
38 | * Get algorithm name for Java Cryptography Architecture operations
39 | *
40 | * @return Algorithm name
41 | */
42 | String getAlgorithm() {
43 | return algorithm;
44 | }
45 |
46 | /**
47 | * Get key length in bytes
48 | *
49 | * @return Key length in bytes
50 | */
51 | int getKeyLength() {
52 | return keyLength;
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/jagged-ssh/src/main/java/com/exceptionfactory/jagged/ssh/EmptyInputKey.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Jagged Contributors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.exceptionfactory.jagged.ssh;
17 |
18 | import com.exceptionfactory.jagged.framework.crypto.MacKey;
19 |
20 | /**
21 | * Empty Input Key extension of Message Authentication Code Key for HKDF from salt key
22 | */
23 | final class EmptyInputKey extends MacKey {
24 | private static final byte[] EMPTY = new byte[]{};
25 |
26 | /**
27 | * Empty Input Key constructor
28 | *
29 | */
30 | EmptyInputKey() {
31 | super(EMPTY, SshEd25519KeyType.EMPTY);
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/jagged-ssh/src/main/java/com/exceptionfactory/jagged/ssh/KeyPairReader.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Jagged Contributors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.exceptionfactory.jagged.ssh;
17 |
18 | import java.nio.ByteBuffer;
19 | import java.security.GeneralSecurityException;
20 | import java.security.KeyPair;
21 |
22 | /**
23 | * Reader abstraction for loading Public and Private Key Pairs
24 | */
25 | interface KeyPairReader {
26 | /**
27 | * Read Public and Private Key Pair
28 | *
29 | * @param inputBuffer Input Buffer to be read
30 | * @return Public and Private Key Pair
31 | * @throws GeneralSecurityException Thrown on failures to parse input buffer
32 | */
33 | KeyPair read(ByteBuffer inputBuffer) throws GeneralSecurityException;
34 | }
35 |
--------------------------------------------------------------------------------
/jagged-ssh/src/main/java/com/exceptionfactory/jagged/ssh/KeySeparator.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Jagged Contributors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.exceptionfactory.jagged.ssh;
17 |
18 | /**
19 | * Separator for encoded key elements
20 | */
21 | enum KeySeparator {
22 | /** Line Feed Character */
23 | LINE_FEED(10),
24 |
25 | /** Carriage Return Character */
26 | CARRIAGE_RETURN(13);
27 |
28 | private final byte code;
29 |
30 | KeySeparator(final int code) {
31 | this.code = (byte) code;
32 | }
33 |
34 | byte getCode() {
35 | return code;
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/jagged-ssh/src/main/java/com/exceptionfactory/jagged/ssh/OpenSshKeyIndicator.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Jagged Contributors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.exceptionfactory.jagged.ssh;
17 |
18 | import java.nio.charset.StandardCharsets;
19 |
20 | /**
21 | * OpenSSH Key Version 1 indicator fields
22 | */
23 | enum OpenSshKeyIndicator {
24 | /** PEM Header */
25 | HEADER("-----BEGIN OPENSSH PRIVATE KEY-----"),
26 |
27 | /** PEM Footer */
28 | FOOTER("-----END OPENSSH PRIVATE KEY-----"),
29 |
30 | /** AUTH_MAGIC Header defined in openssh-portable/PROTOCOL.key */
31 | MAGIC_HEADER("openssh-key-v1\0"),
32 |
33 | /** Cipher Name None indicating no encryption */
34 | CIPHER_NAME_NONE("none");
35 |
36 | private final byte[] indicator;
37 |
38 | OpenSshKeyIndicator(final String indicator) {
39 | this.indicator = indicator.getBytes(StandardCharsets.UTF_8);
40 | }
41 |
42 | byte[] getIndicator() {
43 | return indicator.clone();
44 | }
45 |
46 | int getLength() {
47 | return indicator.length;
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/jagged-ssh/src/main/java/com/exceptionfactory/jagged/ssh/PublicKeyFingerprintProducer.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Jagged Contributors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.exceptionfactory.jagged.ssh;
17 |
18 | import java.security.GeneralSecurityException;
19 |
20 | /**
21 | * Abstraction for generating fingerprints of Public Keys
22 | */
23 | interface PublicKeyFingerprintProducer {
24 | /**
25 | * Get fingerprint from marshalled Public Key bytes
26 | *
27 | * @param marshalledPublicKey Marshalled public key
28 | * @return Fingerprint label
29 | * @throws GeneralSecurityException Thrown on failures to generate fingerprints
30 | */
31 | String getFingerprint(byte[] marshalledPublicKey) throws GeneralSecurityException;
32 | }
33 |
--------------------------------------------------------------------------------
/jagged-ssh/src/main/java/com/exceptionfactory/jagged/ssh/PublicKeyMarshaller.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Jagged Contributors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.exceptionfactory.jagged.ssh;
17 |
18 | import java.security.PublicKey;
19 |
20 | /**
21 | * SSH Public Key Marshaller abstraction for writing Public Key elements according to SSH wire format requirements
22 | *
23 | * @param Public Key Type
24 | */
25 | interface PublicKeyMarshaller {
26 | /**
27 | * Get Public Key marshalled according to SSH wire format requirements
28 | *
29 | * @param publicKey Public Key to be marshalled
30 | * @return Byte array containing marshalled public key
31 | */
32 | byte[] getMarshalledKey(T publicKey);
33 | }
34 |
--------------------------------------------------------------------------------
/jagged-ssh/src/main/java/com/exceptionfactory/jagged/ssh/PublicKeyReader.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Jagged Contributors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.exceptionfactory.jagged.ssh;
17 |
18 | import java.nio.ByteBuffer;
19 | import java.security.GeneralSecurityException;
20 | import java.security.PublicKey;
21 |
22 | /**
23 | * Reader abstraction for loading Public Keys
24 | *
25 | * @param Public Key Type
26 | */
27 | interface PublicKeyReader {
28 | /**
29 | * Read Public Key
30 | *
31 | * @param inputBuffer Input Buffer to be read
32 | * @return Public Key
33 | * @throws GeneralSecurityException Thrown on failures to parse input buffer
34 | */
35 | T read(ByteBuffer inputBuffer) throws GeneralSecurityException;
36 | }
37 |
--------------------------------------------------------------------------------
/jagged-ssh/src/main/java/com/exceptionfactory/jagged/ssh/RsaPublicKeyFactory.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Jagged Contributors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.exceptionfactory.jagged.ssh;
17 |
18 | import java.security.GeneralSecurityException;
19 | import java.security.interfaces.RSAPrivateCrtKey;
20 | import java.security.interfaces.RSAPublicKey;
21 |
22 | /**
23 | * Abstraction for deriving RSA Public Keys from RSA Private Keys
24 | */
25 | interface RsaPublicKeyFactory {
26 | /**
27 | * Get RSA Public Key
28 | *
29 | * @param privateKey RSA Private Key
30 | * @return RSA Public Key
31 | * @throws GeneralSecurityException Thrown on failure to convert private key to public key
32 | */
33 | RSAPublicKey getPublicKey(RSAPrivateCrtKey privateKey) throws GeneralSecurityException;
34 | }
35 |
--------------------------------------------------------------------------------
/jagged-ssh/src/main/java/com/exceptionfactory/jagged/ssh/SharedSecretKeyProducer.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Jagged Contributors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.exceptionfactory.jagged.ssh;
17 |
18 | import com.exceptionfactory.jagged.framework.crypto.SharedSecretKey;
19 |
20 | import java.security.GeneralSecurityException;
21 | import java.security.PublicKey;
22 |
23 | /**
24 | * Abstraction around javax.crypto.KeyAgreement for Shared Secret Key production
25 | */
26 | interface SharedSecretKeyProducer {
27 | /**
28 | * Get Shared Secret Key using provided Public Key
29 | *
30 | * @param publicKey Public Key
31 | * @return Shared Secret Key
32 | * @throws GeneralSecurityException Thrown on failures to produce Shared Secret Key
33 | */
34 | SharedSecretKey getSharedSecretKey(PublicKey publicKey) throws GeneralSecurityException;
35 | }
36 |
--------------------------------------------------------------------------------
/jagged-ssh/src/main/java/com/exceptionfactory/jagged/ssh/SharedWrapKeyProducer.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Jagged Contributors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.exceptionfactory.jagged.ssh;
17 |
18 | import com.exceptionfactory.jagged.framework.crypto.CipherKey;
19 | import com.exceptionfactory.jagged.framework.crypto.SharedSecretKey;
20 |
21 | import java.security.GeneralSecurityException;
22 | import java.security.PublicKey;
23 |
24 | /**
25 | * Abstraction for producing Wrap Key from Shared Secret Key using HMAC-based Extract-and-Expand Key Derivation Function described in RFC 5869
26 | */
27 | interface SharedWrapKeyProducer {
28 | /**
29 | * Get Wrap Key using shared secret key and ephemeral public key
30 | *
31 | * @param sharedSecretKey Shared Secret Key
32 | * @param ephemeralPublicKey Ephemeral Public Key from Recipient Stanza Arguments
33 | * @return Recipient Stanza Cipher Key for decrypting File Key
34 | * @throws GeneralSecurityException Thrown on key derivation failures
35 | */
36 | CipherKey getWrapKey(SharedSecretKey sharedSecretKey, PublicKey ephemeralPublicKey) throws GeneralSecurityException;
37 | }
38 |
--------------------------------------------------------------------------------
/jagged-ssh/src/main/java/com/exceptionfactory/jagged/ssh/SshEd25519DerivedKey.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Jagged Contributors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.exceptionfactory.jagged.ssh;
17 |
18 | import com.exceptionfactory.jagged.framework.crypto.MacKey;
19 |
20 | /**
21 | * SSH Ed25519 Derived Key containing results of HKDF-SHA-256 from marshalled SSH public key
22 | */
23 | final class SshEd25519DerivedKey extends MacKey {
24 | /**
25 | * SSH Ed25519 Derived Public Key constructor with required key
26 | *
27 | * @param key Derived Key consisting of 32 bytes
28 | */
29 | SshEd25519DerivedKey(final byte[] key) {
30 | super(key, SshEd25519KeyType.DERIVED);
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/jagged-ssh/src/main/java/com/exceptionfactory/jagged/ssh/SshEd25519KeyType.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Jagged Contributors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.exceptionfactory.jagged.ssh;
17 |
18 | import com.exceptionfactory.jagged.framework.crypto.CryptographicKeyDescription;
19 |
20 | /**
21 | * SSH Ed25519 Key Type references for construction and validation
22 | */
23 | enum SshEd25519KeyType implements CryptographicKeyDescription {
24 | /** Derived Secret Key */
25 | DERIVED(32),
26 |
27 | /** Empty Input Key for HKDF-SHA-256 */
28 | EMPTY(0),
29 |
30 | /** Marshalled Public Key */
31 | MARSHALLED(51);
32 |
33 | private final int keyLength;
34 |
35 | SshEd25519KeyType(final int keyLength) {
36 | this.keyLength = keyLength;
37 | }
38 |
39 | /**
40 | * Get key length in bytes
41 | *
42 | * @return Key length in bytes
43 | */
44 | @Override
45 | public int getKeyLength() {
46 | return keyLength;
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/jagged-ssh/src/main/java/com/exceptionfactory/jagged/ssh/SshEd25519MarshalledKey.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Jagged Contributors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.exceptionfactory.jagged.ssh;
17 |
18 | import com.exceptionfactory.jagged.framework.crypto.MacKey;
19 |
20 | /**
21 | * SSH Ed25519 Marshalled Public Key containing marshalled SSH public key bytes
22 | */
23 | final class SshEd25519MarshalledKey extends MacKey {
24 | /**
25 | * SSH Ed25519 Marshalled Public Key constructor with required key
26 | *
27 | * @param key Marshalled Key consisting of 51 bytes
28 | */
29 | SshEd25519MarshalledKey(final byte[] key) {
30 | super(key, SshEd25519KeyType.MARSHALLED);
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/jagged-ssh/src/main/java/com/exceptionfactory/jagged/ssh/SshEd25519OpenSshKeyPairReader.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Jagged Contributors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.exceptionfactory.jagged.ssh;
17 |
18 | import java.nio.ByteBuffer;
19 | import java.security.GeneralSecurityException;
20 | import java.security.KeyPair;
21 |
22 | /**
23 | * SSH Ed25519 implementation reads the Ed25519 Private Key portion of an OpenSSH Version 1 Key
24 | */
25 | class SshEd25519OpenSshKeyPairReader extends OpenSshKeyByteBufferReader {
26 | /**
27 | * Read Ed25519 Key Pair from bytes
28 | *
29 | * @param buffer Input Buffer to be read
30 | * @return Ed25519 Public and Private Key Pair
31 | * @throws GeneralSecurityException Thrown on failures to parse input buffer
32 | */
33 | @Override
34 | public KeyPair read(final ByteBuffer buffer) throws GeneralSecurityException {
35 | final byte[] publicKeyBlock = readBlock(buffer);
36 | final Ed25519PublicKey publicKey = new Ed25519PublicKey(publicKeyBlock);
37 |
38 | final byte[] privatePublicKeyBlock = readBlock(buffer);
39 | final byte[] privateKeySeed = new byte[EllipticCurveKeyType.ED25519.getKeyLength()];
40 | System.arraycopy(privatePublicKeyBlock, 0, privateKeySeed, 0, privateKeySeed.length);
41 |
42 | final Ed25519PrivateKey privateKey = new Ed25519PrivateKey(privateKeySeed);
43 | return new KeyPair(publicKey, privateKey);
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/jagged-ssh/src/main/java/com/exceptionfactory/jagged/ssh/SshEd25519PublicKeyMarshaller.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Jagged Contributors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.exceptionfactory.jagged.ssh;
17 |
18 | import java.nio.ByteBuffer;
19 | import java.nio.charset.StandardCharsets;
20 | import java.security.PublicKey;
21 | import java.util.Objects;
22 |
23 | /**
24 | * SSH Ed25519 implementation of Public Key Marshaller writes the Ed25519 public key along with the key algorithm
25 | */
26 | class SshEd25519PublicKeyMarshaller implements PublicKeyMarshaller {
27 | private static final byte[] SSH_ED25519_ALGORITHM = SshEd25519RecipientIndicator.STANZA_TYPE.getIndicator().getBytes(StandardCharsets.UTF_8);
28 |
29 | private static final int BUFFER_SIZE = 128;
30 |
31 | /**
32 | * Get Public Key marshalled according to SSH wire format requirements
33 | *
34 | * @param publicKey Ed25519 Public Key to be marshalled
35 | * @return Byte array containing marshalled public key with ssh-ed25519 algorithm and public key
36 | */
37 | @Override
38 | public byte[] getMarshalledKey(final PublicKey publicKey) {
39 | Objects.requireNonNull(publicKey, "Public Key required");
40 |
41 | final ByteBuffer buffer = ByteBuffer.allocate(BUFFER_SIZE);
42 | writeBytes(buffer, SSH_ED25519_ALGORITHM);
43 | writeBytes(buffer, publicKey.getEncoded());
44 |
45 | final byte[] marshalledKey = new byte[buffer.position()];
46 | buffer.flip();
47 | buffer.get(marshalledKey);
48 | return marshalledKey;
49 | }
50 |
51 | private void writeBytes(final ByteBuffer buffer, final byte[] bytes) {
52 | buffer.putInt(bytes.length);
53 | buffer.put(bytes);
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/jagged-ssh/src/main/java/com/exceptionfactory/jagged/ssh/SshEd25519PublicKeyReader.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Jagged Contributors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.exceptionfactory.jagged.ssh;
17 |
18 | import java.nio.ByteBuffer;
19 | import java.security.GeneralSecurityException;
20 | import java.security.InvalidKeyException;
21 |
22 | /**
23 | * SSH Ed25519 Public Key Reader implementation based on ssh-ed25519 format described in RFC 8709 Section 4
24 | */
25 | class SshEd25519PublicKeyReader extends SshPublicKeyReader {
26 | /**
27 | * SSH Ed25519 Public Key Reader constructor configures the expected ssh-ed25519 algorithm
28 | */
29 | SshEd25519PublicKeyReader() {
30 | super(SshEd25519RecipientIndicator.STANZA_TYPE.getIndicator());
31 | }
32 |
33 | /**
34 | * Read Ed25519 Public Key from block of 32 bytes
35 | *
36 | * @param decodedBuffer Buffer of bytes decoded from Base64 public key
37 | * @return Ed25519 Public Key
38 | * @throws GeneralSecurityException Thrown when block length not equal to expected key length
39 | */
40 | @Override
41 | protected Ed25519PublicKey readPublicKey(final ByteBuffer decodedBuffer) throws GeneralSecurityException {
42 | final byte[] block = readBlock(decodedBuffer);
43 | if (EllipticCurveKeyType.ED25519.getKeyLength() == block.length) {
44 | return new Ed25519PublicKey(block);
45 | } else {
46 | final String message = String.format("Public key length [%d] not expected [%d]", block.length, EllipticCurveKeyType.ED25519.getKeyLength());
47 | throw new InvalidKeyException(message);
48 | }
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/jagged-ssh/src/main/java/com/exceptionfactory/jagged/ssh/SshEd25519RecipientIndicator.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Jagged Contributors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.exceptionfactory.jagged.ssh;
17 |
18 | /**
19 | * SSH Ed25519 Recipient Indicators for reading and writing Recipient Stanzas
20 | */
21 | enum SshEd25519RecipientIndicator {
22 | /** SSH Ed25519 Recipient Stanza Type */
23 | STANZA_TYPE("ssh-ed25519"),
24 |
25 | /** Key Information used for HKDF-SHA-256 */
26 | KEY_INFORMATION("age-encryption.org/v1/ssh-ed25519");
27 |
28 | private final String indicator;
29 |
30 | SshEd25519RecipientIndicator(final String indicator) {
31 | this.indicator = indicator;
32 | }
33 |
34 | public String getIndicator() {
35 | return indicator;
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/jagged-ssh/src/main/java/com/exceptionfactory/jagged/ssh/SshKeyType.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Jagged Contributors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.exceptionfactory.jagged.ssh;
17 |
18 | /**
19 | * SSH Key Types
20 | */
21 | enum SshKeyType {
22 | DSS("ssh-dss"),
23 |
24 | ED25519("ssh-ed25519"),
25 |
26 | RSA("ssh-rsa");
27 |
28 | private final String keyType;
29 |
30 | SshKeyType(final String keyType) {
31 | this.keyType = keyType;
32 | }
33 |
34 | String getKeyType() {
35 | return keyType;
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/jagged-ssh/src/main/java/com/exceptionfactory/jagged/ssh/SshRsaRecipientIndicator.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Jagged Contributors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.exceptionfactory.jagged.ssh;
17 |
18 | /**
19 | * SSH RSA Recipient Indicators for reading and writing Recipient Stanzas
20 | */
21 | enum SshRsaRecipientIndicator {
22 | /** SSH RSA Recipient Stanza Type */
23 | STANZA_TYPE("ssh-rsa"),
24 |
25 | /** Label used for RSA OAEP encryption */
26 | ENCODING_LABEL("age-encryption.org/v1/ssh-rsa");
27 |
28 | private final String indicator;
29 |
30 | SshRsaRecipientIndicator(final String indicator) {
31 | this.indicator = indicator;
32 | }
33 |
34 | public String getIndicator() {
35 | return indicator;
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/jagged-ssh/src/main/java/com/exceptionfactory/jagged/ssh/SshRsaRecipientStanza.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Jagged Contributors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.exceptionfactory.jagged.ssh;
17 |
18 | import com.exceptionfactory.jagged.RecipientStanza;
19 |
20 | import java.util.Collections;
21 | import java.util.List;
22 | import java.util.Objects;
23 |
24 | /**
25 | * SSH RSA Recipient Stanza with standard type and arguments containing encoded public key fingerprint
26 | */
27 | class SshRsaRecipientStanza implements RecipientStanza {
28 | private final List arguments;
29 |
30 | private final byte[] body;
31 |
32 | SshRsaRecipientStanza(final String keyFingerprint, final byte[] body) {
33 | Objects.requireNonNull(keyFingerprint, "Key fingerprint required");
34 | this.arguments = Collections.singletonList(keyFingerprint);
35 | this.body = Objects.requireNonNull(body, "Stanza Body required");
36 | }
37 |
38 | /**
39 | * Get Recipient Stanza Type returns ssh-rsa
40 | *
41 | * @return SSH RSA Type
42 | */
43 | @Override
44 | public String getType() {
45 | return SshRsaRecipientIndicator.STANZA_TYPE.getIndicator();
46 | }
47 |
48 | /**
49 | * Get Recipient Stanza Arguments containing the key fingerprint
50 | *
51 | * @return Recipient Stanza Arguments
52 | */
53 | @Override
54 | public List getArguments() {
55 | return arguments;
56 | }
57 |
58 | /**
59 | * Get Recipient Stanza Body containing encrypted File Key
60 | *
61 | * @return Encrypted File Key body
62 | */
63 | @Override
64 | public byte[] getBody() {
65 | return body.clone();
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/jagged-ssh/src/main/java/com/exceptionfactory/jagged/ssh/StandardRsaPublicKeyFactory.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Jagged Contributors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.exceptionfactory.jagged.ssh;
17 |
18 | import java.security.GeneralSecurityException;
19 | import java.security.KeyFactory;
20 | import java.security.interfaces.RSAPrivateCrtKey;
21 | import java.security.interfaces.RSAPublicKey;
22 | import java.security.spec.RSAPublicKeySpec;
23 | import java.util.Objects;
24 |
25 | /**
26 | * Standard implementation of RSA Public Key Factory
27 | */
28 | class StandardRsaPublicKeyFactory implements RsaPublicKeyFactory {
29 | /**
30 | * Get RSA Public Key
31 | *
32 | * @param privateKey RSA Private Key
33 | * @return RSA Public Key
34 | * @throws GeneralSecurityException Thrown on failure to convert private key to public key
35 | */
36 | @Override
37 | public RSAPublicKey getPublicKey(final RSAPrivateCrtKey privateKey) throws GeneralSecurityException {
38 | Objects.requireNonNull(privateKey, "RSA Private Key required");
39 |
40 | final KeyFactory keyFactory = KeyFactory.getInstance(privateKey.getAlgorithm());
41 | final RSAPublicKeySpec publicKeySpec = new RSAPublicKeySpec(privateKey.getModulus(), privateKey.getPublicExponent());
42 | return (RSAPublicKey) keyFactory.generatePublic(publicKeySpec);
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/jagged-ssh/src/main/java/com/exceptionfactory/jagged/ssh/X25519BasePointPublicKey.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Jagged Contributors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.exceptionfactory.jagged.ssh;
17 |
18 | import java.security.PublicKey;
19 |
20 | /**
21 | * Curve25519 Base Point Public Key as described in RFC 7748 Section 4.1
22 | */
23 | class X25519BasePointPublicKey implements PublicKey {
24 | private static final byte BASE_POINT = 9;
25 |
26 | private static final String FORMAT = "RAW";
27 |
28 | private static final byte[] BASE_POINT_PUBLIC_KEY = new byte[EllipticCurveKeyType.X25519.getKeyLength()];
29 |
30 | static {
31 | BASE_POINT_PUBLIC_KEY[0] = BASE_POINT;
32 | }
33 |
34 | /**
35 | * Get algorithm returns X25519 for Key Agreement operations
36 | *
37 | * @return X25519 algorithm
38 | */
39 | @Override
40 | public String getAlgorithm() {
41 | return EllipticCurveKeyType.X25519.getAlgorithm();
42 | }
43 |
44 | /**
45 | * Get format returns RAW
46 | *
47 | * @return RAW format
48 | */
49 | @Override
50 | public String getFormat() {
51 | return FORMAT;
52 | }
53 |
54 | /**
55 | * Get encoded Base Point Public Key as 32 bytes with leading 9 following RFC 7748 Section 4.1
56 | *
57 | * @return Base Point Public Key as 32 bytes
58 | */
59 | @Override
60 | public byte[] getEncoded() {
61 | return BASE_POINT_PUBLIC_KEY.clone();
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/jagged-ssh/src/main/java/com/exceptionfactory/jagged/ssh/X25519KeyPairGeneratorFactory.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Jagged Contributors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.exceptionfactory.jagged.ssh;
17 |
18 | import java.security.KeyPairGenerator;
19 | import java.security.NoSuchAlgorithmException;
20 | import java.security.Provider;
21 | import java.util.Objects;
22 |
23 | /**
24 | * Factory abstraction for instances of javax.security.KeyPairGenerator with X25519
25 | */
26 | final class X25519KeyPairGeneratorFactory {
27 | private final Provider provider;
28 |
29 | /**
30 | * Key Pair Generator Factory default constructor uses the system default Security Provider configuration
31 | */
32 | X25519KeyPairGeneratorFactory() {
33 | provider = null;
34 | }
35 |
36 | /**
37 | * Key Pair Generator Factory constructor with support for custom Security Provider
38 | *
39 | * @param provider Security Provider supporting X25519
40 | */
41 | X25519KeyPairGeneratorFactory(final Provider provider) {
42 | this.provider = Objects.requireNonNull(provider, "Provider required");
43 | }
44 |
45 | KeyPairGenerator getKeyPairGenerator() throws NoSuchAlgorithmException {
46 | final KeyPairGenerator keyPairGenerator;
47 |
48 | if (provider == null) {
49 | keyPairGenerator = KeyPairGenerator.getInstance(EllipticCurveKeyType.X25519.getAlgorithm());
50 | } else {
51 | keyPairGenerator = KeyPairGenerator.getInstance(EllipticCurveKeyType.X25519.getAlgorithm(), provider);
52 | }
53 |
54 | return keyPairGenerator;
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/jagged-ssh/src/test/java/com/exceptionfactory/jagged/ssh/Ed25519KeyPairProvider.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Jagged Contributors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.exceptionfactory.jagged.ssh;
17 |
18 | import com.exceptionfactory.jagged.framework.codec.CanonicalBase64;
19 |
20 | import java.nio.charset.StandardCharsets;
21 |
22 | final class Ed25519KeyPairProvider {
23 |
24 | private static final String PUBLIC_KEY_ENCODED = "HURauP50ZGJDuUkn6tjy/PGQWmTR2FFyDYXP071GP3U";
25 |
26 | private static final String PRIVATE_KEY_ENCODED = "nWNC6CoPYFBs1dSBWSYPFjQ4+APPoH/3DQoB2kCairA";
27 |
28 | private static final CanonicalBase64.Decoder DECODER = CanonicalBase64.getDecoder();
29 |
30 | private static Ed25519PublicKey publicKey;
31 |
32 | private static Ed25519PrivateKey privateKey;
33 |
34 | private Ed25519KeyPairProvider() {
35 |
36 | }
37 |
38 | static synchronized Ed25519PublicKey getPublicKey() {
39 | if (publicKey == null) {
40 | setKeyPair();
41 | }
42 | return publicKey;
43 | }
44 |
45 | static synchronized Ed25519PrivateKey getPrivateKey() {
46 | if (privateKey == null) {
47 | setKeyPair();
48 | }
49 | return privateKey;
50 | }
51 |
52 | private static void setKeyPair() {
53 | final byte[] publicKeyEncoded = DECODER.decode(PUBLIC_KEY_ENCODED.getBytes(StandardCharsets.UTF_8));
54 | publicKey = new Ed25519PublicKey(publicKeyEncoded);
55 |
56 | final byte[] privateKeyEncoded = DECODER.decode(PRIVATE_KEY_ENCODED.getBytes(StandardCharsets.UTF_8));
57 | privateKey = new Ed25519PrivateKey(privateKeyEncoded);
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/jagged-ssh/src/test/java/com/exceptionfactory/jagged/ssh/RsaKeyPairProvider.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Jagged Contributors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.exceptionfactory.jagged.ssh;
17 |
18 | import java.security.KeyPair;
19 | import java.security.KeyPairGenerator;
20 | import java.security.NoSuchAlgorithmException;
21 | import java.security.interfaces.RSAPrivateCrtKey;
22 | import java.security.interfaces.RSAPublicKey;
23 |
24 | final class RsaKeyPairProvider {
25 | private static final String KEY_ALGORITHM = "RSA";
26 |
27 | private static final int KEY_SIZE = 4096;
28 |
29 | private static RSAPublicKey rsaPublicKey;
30 |
31 | private static RSAPrivateCrtKey rsaPrivateCrtKey;
32 |
33 | private RsaKeyPairProvider() {
34 |
35 | }
36 |
37 | static synchronized RSAPublicKey getRsaPublicKey() throws NoSuchAlgorithmException {
38 | if (rsaPublicKey == null) {
39 | setKeyPair();
40 | }
41 | return rsaPublicKey;
42 | }
43 |
44 | static synchronized RSAPrivateCrtKey getRsaPrivateCrtKey() throws NoSuchAlgorithmException {
45 | if (rsaPrivateCrtKey == null) {
46 | setKeyPair();
47 | }
48 | return rsaPrivateCrtKey;
49 | }
50 |
51 | private static void setKeyPair() throws NoSuchAlgorithmException {
52 | final KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(KEY_ALGORITHM);
53 | keyPairGenerator.initialize(KEY_SIZE);
54 | final KeyPair keyPair = keyPairGenerator.generateKeyPair();
55 | rsaPublicKey = (RSAPublicKey) keyPair.getPublic();
56 | rsaPrivateCrtKey = (RSAPrivateCrtKey) keyPair.getPrivate();
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/jagged-ssh/src/test/java/com/exceptionfactory/jagged/ssh/SshEd25519PublicKeyMarshallerTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Jagged Contributors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.exceptionfactory.jagged.ssh;
17 |
18 | import org.junit.jupiter.api.BeforeEach;
19 | import org.junit.jupiter.api.Test;
20 |
21 | import java.util.Arrays;
22 |
23 | import static org.junit.jupiter.api.Assertions.assertArrayEquals;
24 | import static org.junit.jupiter.api.Assertions.assertEquals;
25 | import static org.junit.jupiter.api.Assertions.assertNotNull;
26 |
27 | class SshEd25519PublicKeyMarshallerTest {
28 | private static final byte[] SSH_ED25519_ALGORITHM_SERIALIZED = {0, 0, 0, 11, 115, 115, 104, 45, 101, 100, 50, 53, 53, 49, 57};
29 |
30 | private SshEd25519PublicKeyMarshaller marshaller;
31 |
32 | @BeforeEach
33 | void setMarshaller() {
34 | marshaller = new SshEd25519PublicKeyMarshaller();
35 | }
36 |
37 | @Test
38 | void testGetMarshalledKey() {
39 | final Ed25519PublicKey publicKey = Ed25519KeyPairProvider.getPublicKey();
40 | final byte[] marshalledKey = marshaller.getMarshalledKey(publicKey);
41 |
42 | assertNotNull(marshalledKey);
43 | assertEquals(SshEd25519KeyType.MARSHALLED.getKeyLength(), marshalledKey.length);
44 |
45 | final byte[] algorithm = Arrays.copyOfRange(marshalledKey, 0, SSH_ED25519_ALGORITHM_SERIALIZED.length);
46 | assertArrayEquals(SSH_ED25519_ALGORITHM_SERIALIZED, algorithm);
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/jagged-ssh/src/test/java/com/exceptionfactory/jagged/ssh/StandardPublicKeyFingerprintProducerTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Jagged Contributors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.exceptionfactory.jagged.ssh;
17 |
18 | import org.junit.jupiter.api.BeforeEach;
19 | import org.junit.jupiter.api.Test;
20 |
21 | import java.security.GeneralSecurityException;
22 |
23 | import static org.junit.jupiter.api.Assertions.assertEquals;
24 | import static org.junit.jupiter.api.Assertions.assertNotNull;
25 |
26 | class StandardPublicKeyFingerprintProducerTest {
27 | private static final byte[] PUBLIC_KEY = {0, 1, 2, 3};
28 |
29 | private static final String EXPECTED_FINGERPRINT = "BU7ewQ";
30 |
31 | private StandardPublicKeyFingerprintProducer fingerprintProducer;
32 |
33 | @BeforeEach
34 | void setFingerprintProducer() {
35 | fingerprintProducer = new StandardPublicKeyFingerprintProducer();
36 | }
37 |
38 | @Test
39 | void testGetFingerprint() throws GeneralSecurityException {
40 | final String fingerprint = fingerprintProducer.getFingerprint(PUBLIC_KEY);
41 |
42 | assertNotNull(fingerprint);
43 | assertEquals(EXPECTED_FINGERPRINT, fingerprint);
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/jagged-ssh/src/test/java/com/exceptionfactory/jagged/ssh/X25519BasePointPublicKeyTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Jagged Contributors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.exceptionfactory.jagged.ssh;
17 |
18 | import org.junit.jupiter.api.Test;
19 |
20 | import static org.junit.jupiter.api.Assertions.assertEquals;
21 |
22 | class X25519BasePointPublicKeyTest {
23 | private static final int BASE_POINT = 9;
24 |
25 | private static final String FORMAT = "RAW";
26 |
27 | @Test
28 | void testGetAlgorithm() {
29 | final X25519BasePointPublicKey basePointPublicKey = new X25519BasePointPublicKey();
30 |
31 | assertEquals(EllipticCurveKeyType.X25519.getAlgorithm(), basePointPublicKey.getAlgorithm());
32 | }
33 |
34 | @Test
35 | void testGetFormat() {
36 | final X25519BasePointPublicKey basePointPublicKey = new X25519BasePointPublicKey();
37 |
38 | assertEquals(FORMAT, basePointPublicKey.getFormat());
39 | }
40 |
41 | @Test
42 | void testGetEncoded() {
43 | final X25519BasePointPublicKey basePointPublicKey = new X25519BasePointPublicKey();
44 |
45 | final byte[] encoded = basePointPublicKey.getEncoded();
46 | assertEquals(EllipticCurveKeyType.X25519.getKeyLength(), encoded.length);
47 | assertEquals(BASE_POINT, encoded[0]);
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/jagged-ssh/src/test/java/com/exceptionfactory/jagged/ssh/X25519KeyPairGeneratorFactoryTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Jagged Contributors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.exceptionfactory.jagged.ssh;
17 |
18 | import org.junit.jupiter.api.Test;
19 |
20 | import java.security.KeyPairGenerator;
21 | import java.security.NoSuchAlgorithmException;
22 | import java.security.Provider;
23 | import java.security.Security;
24 |
25 | import static org.junit.jupiter.api.Assertions.assertNotNull;
26 |
27 | class X25519KeyPairGeneratorFactoryTest {
28 | private static final String ALGORITHM_FILTER = String.format("KeyPairGenerator.%s", EllipticCurveKeyType.X25519.getAlgorithm());
29 |
30 | @Test
31 | void testGetKeyPairGenerator() throws NoSuchAlgorithmException {
32 | final X25519KeyPairGeneratorFactory keyPairGeneratorFactory = new X25519KeyPairGeneratorFactory();
33 | final KeyPairGenerator keyPairGenerator = keyPairGeneratorFactory.getKeyPairGenerator();
34 |
35 | assertNotNull(keyPairGenerator);
36 | }
37 |
38 | @Test
39 | void testGetKeyPairGeneratorWithProvider() throws NoSuchAlgorithmException {
40 | final Provider provider = getProvider();
41 | final X25519KeyPairGeneratorFactory keyPairGeneratorFactory = new X25519KeyPairGeneratorFactory(provider);
42 | final KeyPairGenerator keyPairGenerator = keyPairGeneratorFactory.getKeyPairGenerator();
43 |
44 | assertNotNull(keyPairGenerator);
45 | }
46 |
47 | private Provider getProvider() {
48 | final Provider[] providers = Security.getProviders(ALGORITHM_FILTER);
49 | return providers[0];
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/jagged-ssh/src/test/java/com/exceptionfactory/jagged/ssh/X25519SharedSecretKeyProducerTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Jagged Contributors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.exceptionfactory.jagged.ssh;
17 |
18 | import com.exceptionfactory.jagged.framework.crypto.SharedSecretKey;
19 | import org.junit.jupiter.api.Test;
20 |
21 | import java.security.GeneralSecurityException;
22 | import java.security.KeyPair;
23 | import java.security.KeyPairGenerator;
24 |
25 | import static org.junit.jupiter.api.Assertions.assertArrayEquals;
26 |
27 | class X25519SharedSecretKeyProducerTest {
28 |
29 | @Test
30 | void testGetSharedSecretKey() throws GeneralSecurityException {
31 | final KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(EllipticCurveKeyType.X25519.getAlgorithm());
32 |
33 | final KeyPair senderKeyPair = keyPairGenerator.generateKeyPair();
34 | final KeyPair recipientKeyPair = keyPairGenerator.generateKeyPair();
35 |
36 | final X25519KeyAgreementFactory keyAgreementFactory = new X25519KeyAgreementFactory();
37 |
38 | final X25519SharedSecretKeyProducer senderProducer = new X25519SharedSecretKeyProducer(senderKeyPair.getPrivate(), keyAgreementFactory);
39 | final SharedSecretKey senderSharedSecretKey = senderProducer.getSharedSecretKey(recipientKeyPair.getPublic());
40 |
41 | final X25519SharedSecretKeyProducer recipientProducer = new X25519SharedSecretKeyProducer(recipientKeyPair.getPrivate(), keyAgreementFactory);
42 | final SharedSecretKey recipientSharedSecretKey = recipientProducer.getSharedSecretKey(senderKeyPair.getPublic());
43 |
44 | assertArrayEquals(senderSharedSecretKey.getEncoded(), recipientSharedSecretKey.getEncoded());
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/jagged-test/src/test/java/com/exceptionfactory/jagged/test/CommunityCryptographyExpectation.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Jagged Contributors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.exceptionfactory.jagged.test;
17 |
18 | import com.exceptionfactory.jagged.PayloadException;
19 | import com.exceptionfactory.jagged.UnsupportedRecipientStanzaException;
20 | import com.exceptionfactory.jagged.framework.armor.ArmoredDecodingException;
21 |
22 | import java.security.GeneralSecurityException;
23 | import java.security.SignatureException;
24 |
25 | /**
26 | * Community Cryptography Test Vector expected results
27 | */
28 | enum CommunityCryptographyExpectation {
29 | SUCCESS("success", null),
30 |
31 | NO_MATCH("no match", UnsupportedRecipientStanzaException.class),
32 |
33 | HMAC_FAILURE("HMAC failure", SignatureException.class),
34 |
35 | HEADER_FAILURE("header failure", GeneralSecurityException.class),
36 |
37 | PAYLOAD_FAILURE("payload failure", PayloadException.class),
38 |
39 | ARMOR_FAILURE("armor failure", ArmoredDecodingException.class);
40 |
41 | private final String label;
42 |
43 | private final Class extends Exception> exceptionClass;
44 |
45 | CommunityCryptographyExpectation(final String label, final Class extends Exception> exceptionClass) {
46 | this.label = label;
47 | this.exceptionClass = exceptionClass;
48 | }
49 |
50 | String getLabel() {
51 | return label;
52 | }
53 |
54 | Class extends Exception> getExceptionClass() {
55 | return exceptionClass;
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/jagged-test/src/test/java/com/exceptionfactory/jagged/test/CommunityCryptographyProperty.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Jagged Contributors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.exceptionfactory.jagged.test;
17 |
18 | /**
19 | * Standard property names from age encryption Community Cryptography Test Vectors
20 | */
21 | enum CommunityCryptographyProperty {
22 | ARMORED("armored"),
23 |
24 | PAYLOAD("payload"),
25 |
26 | IDENTITY("identity"),
27 |
28 | PASSPHRASE("passphrase"),
29 |
30 | EXPECT("expect");
31 |
32 | private final String property;
33 |
34 | CommunityCryptographyProperty(final String property) {
35 | this.property = property;
36 | }
37 |
38 | String getProperty() {
39 | return property;
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/jagged-test/src/test/resources/java.security:
--------------------------------------------------------------------------------
1 | security.provider.1=org.bouncycastle.jce.provider.BouncyCastleProvider
2 |
--------------------------------------------------------------------------------
/jagged-x25519/src/main/java/com/exceptionfactory/jagged/x25519/BasePointPublicKey.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Jagged Contributors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.exceptionfactory.jagged.x25519;
17 |
18 | import java.security.PublicKey;
19 |
20 | /**
21 | * Curve25519 Base Point Public Key as described in RFC 7748 Section 4.1
22 | */
23 | class BasePointPublicKey implements PublicKey {
24 | private static final byte BASE_POINT = 9;
25 |
26 | private static final String FORMAT = "RAW";
27 |
28 | private static final byte[] BASE_POINT_PUBLIC_KEY = new byte[RecipientKeyType.X25519.getKeyLength()];
29 |
30 | static {
31 | BASE_POINT_PUBLIC_KEY[0] = BASE_POINT;
32 | }
33 |
34 | /**
35 | * Get algorithm returns X25519 for Key Agreement operations
36 | *
37 | * @return X25519 algorithm
38 | */
39 | @Override
40 | public String getAlgorithm() {
41 | return RecipientIndicator.KEY_ALGORITHM.getIndicator();
42 | }
43 |
44 | /**
45 | * Get format returns RAW
46 | *
47 | * @return RAW format
48 | */
49 | @Override
50 | public String getFormat() {
51 | return FORMAT;
52 | }
53 |
54 | /**
55 | * Get encoded Base Point Public Key as 32 bytes with leading 9 following RFC 7748 Section 4.1
56 | *
57 | * @return Base Point Public Key as 32 bytes
58 | */
59 | @Override
60 | public byte[] getEncoded() {
61 | return BASE_POINT_PUBLIC_KEY.clone();
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/jagged-x25519/src/main/java/com/exceptionfactory/jagged/x25519/IdentityIndicator.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Jagged Contributors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.exceptionfactory.jagged.x25519;
17 |
18 | /**
19 | * X2559 Identity Indicators for reading and writing Identities
20 | */
21 | enum IdentityIndicator {
22 | /** Bech32 Encoded Private Human-Readable Part */
23 | PRIVATE_KEY_HUMAN_READABLE_PART("AGE-SECRET-KEY-");
24 |
25 | private final String indicator;
26 |
27 | IdentityIndicator(final String indicator) {
28 | this.indicator = indicator;
29 | }
30 |
31 | public String getIndicator() {
32 | return indicator;
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/jagged-x25519/src/main/java/com/exceptionfactory/jagged/x25519/KeyPairGeneratorFactory.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Jagged Contributors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.exceptionfactory.jagged.x25519;
17 |
18 | import java.security.KeyPairGenerator;
19 | import java.security.NoSuchAlgorithmException;
20 | import java.security.Provider;
21 | import java.util.Objects;
22 |
23 | /**
24 | * Factory abstraction for instances of javax.security.KeyPairGenerator with X25519
25 | */
26 | final class KeyPairGeneratorFactory {
27 | private final Provider provider;
28 |
29 | /**
30 | * Key Pair Generator Factory default constructor uses the system default Security Provider configuration
31 | */
32 | KeyPairGeneratorFactory() {
33 | provider = null;
34 | }
35 |
36 | /**
37 | * Key Pair Generator Factory constructor with support for custom Security Provider
38 | *
39 | * @param provider Security Provider supporting X25519
40 | */
41 | KeyPairGeneratorFactory(final Provider provider) {
42 | this.provider = Objects.requireNonNull(provider, "Provider required");
43 | }
44 |
45 | KeyPairGenerator getKeyPairGenerator() throws NoSuchAlgorithmException {
46 | final KeyPairGenerator keyPairGenerator;
47 |
48 | if (provider == null) {
49 | keyPairGenerator = KeyPairGenerator.getInstance(RecipientIndicator.KEY_ALGORITHM.getIndicator());
50 | } else {
51 | keyPairGenerator = KeyPairGenerator.getInstance(RecipientIndicator.KEY_ALGORITHM.getIndicator(), provider);
52 | }
53 |
54 | return keyPairGenerator;
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/jagged-x25519/src/main/java/com/exceptionfactory/jagged/x25519/RecipientIndicator.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Jagged Contributors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.exceptionfactory.jagged.x25519;
17 |
18 | /**
19 | * X2559 Recipient Indicators for reading and writing Recipient Stanzas
20 | */
21 | enum RecipientIndicator {
22 | /** Bech32 Encoded Public Key Human-Readable Part */
23 | PUBLIC_KEY_HUMAN_READABLE_PART("age"),
24 |
25 | /** Recipient Stanza Type */
26 | STANZA_TYPE("X25519"),
27 |
28 | /** Key Algorithm for cryptographic operations with Diffie-Hellman Key Exchange using Curve25519 */
29 | KEY_ALGORITHM("X25519"),
30 |
31 | /** HKDF-SHA-256 Key Information */
32 | KEY_INFORMATION("age-encryption.org/v1/X25519");
33 |
34 | private final String indicator;
35 |
36 | RecipientIndicator(final String indicator) {
37 | this.indicator = indicator;
38 | }
39 |
40 | public String getIndicator() {
41 | return indicator;
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/jagged-x25519/src/main/java/com/exceptionfactory/jagged/x25519/RecipientKeyFactory.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Jagged Contributors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.exceptionfactory.jagged.x25519;
17 |
18 | import java.security.GeneralSecurityException;
19 | import java.security.PrivateKey;
20 | import java.security.PublicKey;
21 |
22 | /**
23 | * Abstraction for producing Java Cryptography Public Key and Private Key objects from binary representations
24 | */
25 | interface RecipientKeyFactory {
26 | /**
27 | * Get Public Key from encoded binary
28 | *
29 | * @param publicKeyEncoded Encoded public key
30 | * @return Public Key
31 | * @throws GeneralSecurityException Thrown on key processing failures
32 | */
33 | PublicKey getPublicKey(byte[] publicKeyEncoded) throws GeneralSecurityException;
34 |
35 | /**
36 | * Get Private Key from encoded binary
37 | *
38 | * @param privateKeyEncoded Encoded private key
39 | * @return Private Key
40 | * @throws GeneralSecurityException Thrown on key processing failures
41 | */
42 | PrivateKey getPrivateKey(byte[] privateKeyEncoded) throws GeneralSecurityException;
43 | }
44 |
--------------------------------------------------------------------------------
/jagged-x25519/src/main/java/com/exceptionfactory/jagged/x25519/RecipientKeyType.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Jagged Contributors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.exceptionfactory.jagged.x25519;
17 |
18 | /**
19 | * Recipient Key Type enumerates standard properties for X25519 keys
20 | */
21 | enum RecipientKeyType {
22 | /** Curve25519 coordinate key of 32 bytes for X25519 key agreement operations */
23 | X25519(32);
24 |
25 | private final int keyLength;
26 |
27 | RecipientKeyType(final int keyLength) {
28 | this.keyLength = keyLength;
29 | }
30 |
31 | /**
32 | * Get key length in bytes
33 | *
34 | * @return Key length in bytes
35 | */
36 | public int getKeyLength() {
37 | return keyLength;
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/jagged-x25519/src/main/java/com/exceptionfactory/jagged/x25519/SharedSecretKeyProducer.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Jagged Contributors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.exceptionfactory.jagged.x25519;
17 |
18 | import com.exceptionfactory.jagged.framework.crypto.SharedSecretKey;
19 |
20 | import java.security.GeneralSecurityException;
21 | import java.security.PublicKey;
22 |
23 | /**
24 | * Abstraction around javax.crypto.KeyAgreement for Shared Secret Key production
25 | */
26 | interface SharedSecretKeyProducer {
27 | /**
28 | * Get Shared Secret Key using provided Public Key
29 | *
30 | * @param publicKey Public Key
31 | * @return Shared Secret Key
32 | * @throws GeneralSecurityException Thrown on failures to produced Shared Secret Key
33 | */
34 | SharedSecretKey getSharedSecretKey(PublicKey publicKey) throws GeneralSecurityException;
35 | }
36 |
--------------------------------------------------------------------------------
/jagged-x25519/src/main/java/com/exceptionfactory/jagged/x25519/SharedWrapKeyProducer.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Jagged Contributors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.exceptionfactory.jagged.x25519;
17 |
18 | import com.exceptionfactory.jagged.framework.crypto.CipherKey;
19 | import com.exceptionfactory.jagged.framework.crypto.SharedSecretKey;
20 |
21 | import java.security.GeneralSecurityException;
22 | import java.security.PublicKey;
23 |
24 | /**
25 | * Abstraction for producing Wrap Key from Shared Secret Key using HMAC-based Extract-and-Expand Key Derivation Function described in RFC 5869
26 | */
27 | interface SharedWrapKeyProducer {
28 | /**
29 | * Get Wrap Key using shared secret key and ephemeral public key
30 | *
31 | * @param sharedSecretKey Shared Secret Key
32 | * @param ephemeralPublicKey Ephemeral Public Key decoded from Recipient Stanza Arguments
33 | * @return Recipient Stanza Cipher Key for decrypting File Key
34 | * @throws GeneralSecurityException Thrown on key derivation failures
35 | */
36 | CipherKey getWrapKey(SharedSecretKey sharedSecretKey, PublicKey ephemeralPublicKey) throws GeneralSecurityException;
37 | }
38 |
--------------------------------------------------------------------------------
/jagged-x25519/src/main/java/com/exceptionfactory/jagged/x25519/X25519KeyFactory.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Jagged Contributors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.exceptionfactory.jagged.x25519;
17 |
18 | import java.security.GeneralSecurityException;
19 | import java.security.KeyFactory;
20 | import java.security.Provider;
21 |
22 | /**
23 | * X25519 Key Factory capable of translating Key Specifications encoded according to age-encryption.org to Public Keys
24 | */
25 | public final class X25519KeyFactory extends KeyFactory {
26 | /**
27 | * X25519 Key Factory constructor with default Security Provider
28 | *
29 | * @throws GeneralSecurityException Thrown on failures to construct required collaborators
30 | */
31 | public X25519KeyFactory() throws GeneralSecurityException {
32 | this(new KeyAgreementFactory(), new KeyPairGeneratorFactory());
33 | }
34 |
35 | /**
36 | * X25519 Key Factory constructor with specified Security Provider
37 | *
38 | * @param provider Security Provider for X25519 algorithm implementation resolution
39 | * @throws GeneralSecurityException Thrown on failures to construct required collaborators
40 | */
41 | public X25519KeyFactory(final Provider provider) throws GeneralSecurityException {
42 | this(new KeyAgreementFactory(provider), new KeyPairGeneratorFactory(provider));
43 | }
44 |
45 | private X25519KeyFactory(final KeyAgreementFactory keyAgreementFactory, final KeyPairGeneratorFactory keyPairGeneratorFactory) throws GeneralSecurityException {
46 | super(new X25519KeyFactorySpi(keyAgreementFactory, new StandardRecipientKeyFactory(keyPairGeneratorFactory)), null, RecipientIndicator.KEY_ALGORITHM.getIndicator());
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/jagged-x25519/src/main/java/com/exceptionfactory/jagged/x25519/X25519RecipientStanza.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Jagged Contributors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.exceptionfactory.jagged.x25519;
17 |
18 | import com.exceptionfactory.jagged.RecipientStanza;
19 |
20 | import java.util.Collections;
21 | import java.util.List;
22 | import java.util.Objects;
23 |
24 | /**
25 | * X25519 Recipient Stanza with standard type and single argument containing ephemeral shared public key
26 | */
27 | class X25519RecipientStanza implements RecipientStanza {
28 | private final List arguments;
29 |
30 | private final byte[] body;
31 |
32 | X25519RecipientStanza(final String ephemeralShare, final byte[] body) {
33 | this.arguments = Collections.singletonList(Objects.requireNonNull(ephemeralShare, "Ephemeral Share required"));
34 | this.body = Objects.requireNonNull(body, "Stanza Body required");
35 | }
36 |
37 | /**
38 | * Get Recipient Stanza Type returns X25519
39 | *
40 | * @return X25519 Type
41 | */
42 | @Override
43 | public String getType() {
44 | return RecipientIndicator.STANZA_TYPE.getIndicator();
45 | }
46 |
47 | /**
48 | * Get Recipient Stanza Arguments containing the ephemeral share encoded
49 | *
50 | * @return Recipient Stanza Arguments
51 | */
52 | @Override
53 | public List getArguments() {
54 | return arguments;
55 | }
56 |
57 | /**
58 | * Get Recipient Stanza Body containing encrypted File Key with a length of 32 bytes
59 | *
60 | * @return Encrypted File Key body of 32 bytes
61 | */
62 | @Override
63 | public byte[] getBody() {
64 | return body.clone();
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/jagged-x25519/src/test/java/com/exceptionfactory/jagged/x25519/BasePointPublicKeyTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Jagged Contributors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.exceptionfactory.jagged.x25519;
17 |
18 | import org.junit.jupiter.api.Test;
19 |
20 | import static org.junit.jupiter.api.Assertions.assertEquals;
21 |
22 | class BasePointPublicKeyTest {
23 | private static final int BASE_POINT = 9;
24 |
25 | private static final String FORMAT = "RAW";
26 |
27 | @Test
28 | void testGetAlgorithm() {
29 | final BasePointPublicKey basePointPublicKey = new BasePointPublicKey();
30 |
31 | assertEquals(RecipientIndicator.KEY_ALGORITHM.getIndicator(), basePointPublicKey.getAlgorithm());
32 | }
33 |
34 | @Test
35 | void testGetFormat() {
36 | final BasePointPublicKey basePointPublicKey = new BasePointPublicKey();
37 |
38 | assertEquals(FORMAT, basePointPublicKey.getFormat());
39 | }
40 |
41 | @Test
42 | void testGetEncoded() {
43 | final BasePointPublicKey basePointPublicKey = new BasePointPublicKey();
44 |
45 | final byte[] encoded = basePointPublicKey.getEncoded();
46 | assertEquals(RecipientKeyType.X25519.getKeyLength(), encoded.length);
47 | assertEquals(BASE_POINT, encoded[0]);
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/jagged-x25519/src/test/java/com/exceptionfactory/jagged/x25519/KeyPairGeneratorFactoryTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Jagged Contributors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.exceptionfactory.jagged.x25519;
17 |
18 | import org.junit.jupiter.api.Test;
19 |
20 | import java.security.KeyPairGenerator;
21 | import java.security.NoSuchAlgorithmException;
22 | import java.security.Provider;
23 | import java.security.Security;
24 |
25 | import static org.junit.jupiter.api.Assertions.assertNotNull;
26 |
27 | class KeyPairGeneratorFactoryTest {
28 | private static final String ALGORITHM_FILTER = String.format("KeyPairGenerator.%s", RecipientIndicator.KEY_ALGORITHM.getIndicator());
29 |
30 | @Test
31 | void testGetKeyPairGenerator() throws NoSuchAlgorithmException {
32 | final KeyPairGeneratorFactory keyPairGeneratorFactory = new KeyPairGeneratorFactory();
33 | final KeyPairGenerator keyPairGenerator = keyPairGeneratorFactory.getKeyPairGenerator();
34 |
35 | assertNotNull(keyPairGenerator);
36 | }
37 |
38 | @Test
39 | void testGetKeyPairGeneratorWithProvider() throws NoSuchAlgorithmException {
40 | final Provider provider = getProvider();
41 | final KeyPairGeneratorFactory keyPairGeneratorFactory = new KeyPairGeneratorFactory(provider);
42 | final KeyPairGenerator keyPairGenerator = keyPairGeneratorFactory.getKeyPairGenerator();
43 |
44 | assertNotNull(keyPairGenerator);
45 | }
46 |
47 | private Provider getProvider() {
48 | final Provider[] providers = Security.getProviders(ALGORITHM_FILTER);
49 | return providers[0];
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/jagged-x25519/src/test/java/com/exceptionfactory/jagged/x25519/X25519RecipientStanzaTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Jagged Contributors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.exceptionfactory.jagged.x25519;
17 |
18 | import org.junit.jupiter.api.Test;
19 |
20 | import java.util.Collections;
21 |
22 | import static org.junit.jupiter.api.Assertions.assertArrayEquals;
23 | import static org.junit.jupiter.api.Assertions.assertEquals;
24 |
25 | class X25519RecipientStanzaTest {
26 | private static final byte[] BODY = new byte[]{};
27 |
28 | private static final String EPHEMERAL_SHARE = String.class.getSimpleName();
29 |
30 | @Test
31 | void testGetType() {
32 | final X25519RecipientStanza recipientStanza = new X25519RecipientStanza(EPHEMERAL_SHARE, BODY);
33 |
34 | assertEquals(RecipientIndicator.STANZA_TYPE.getIndicator(), recipientStanza.getType());
35 | }
36 |
37 | @Test
38 | void testGetArguments() {
39 | final X25519RecipientStanza recipientStanza = new X25519RecipientStanza(EPHEMERAL_SHARE, BODY);
40 |
41 | assertEquals(Collections.singletonList(EPHEMERAL_SHARE), recipientStanza.getArguments());
42 | }
43 |
44 | @Test
45 | void testGetBody() {
46 | final X25519RecipientStanza recipientStanza = new X25519RecipientStanza(EPHEMERAL_SHARE, BODY);
47 |
48 | assertArrayEquals(BODY, recipientStanza.getBody());
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/jagged-x25519/src/test/java/com/exceptionfactory/jagged/x25519/X25519SharedSecretKeyProducerTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Jagged Contributors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.exceptionfactory.jagged.x25519;
17 |
18 | import com.exceptionfactory.jagged.framework.crypto.SharedSecretKey;
19 | import org.junit.jupiter.api.Test;
20 |
21 | import java.security.GeneralSecurityException;
22 | import java.security.KeyPair;
23 | import java.security.KeyPairGenerator;
24 |
25 | import static org.junit.jupiter.api.Assertions.assertArrayEquals;
26 |
27 | class X25519SharedSecretKeyProducerTest {
28 |
29 | @Test
30 | void testGetSharedSecretKey() throws GeneralSecurityException {
31 | final KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(RecipientIndicator.KEY_ALGORITHM.getIndicator());
32 |
33 | final KeyPair senderKeyPair = keyPairGenerator.generateKeyPair();
34 | final KeyPair recipientKeyPair = keyPairGenerator.generateKeyPair();
35 |
36 | final KeyAgreementFactory keyAgreementFactory = new KeyAgreementFactory();
37 |
38 | final X25519SharedSecretKeyProducer senderProducer = new X25519SharedSecretKeyProducer(senderKeyPair.getPrivate(), keyAgreementFactory);
39 | final SharedSecretKey senderSharedSecretKey = senderProducer.getSharedSecretKey(recipientKeyPair.getPublic());
40 |
41 | final X25519SharedSecretKeyProducer recipientProducer = new X25519SharedSecretKeyProducer(recipientKeyPair.getPrivate(), keyAgreementFactory);
42 | final SharedSecretKey recipientSharedSecretKey = recipientProducer.getSharedSecretKey(senderKeyPair.getPublic());
43 |
44 | assertArrayEquals(senderSharedSecretKey.getEncoded(), recipientSharedSecretKey.getEncoded());
45 | }
46 | }
47 |
--------------------------------------------------------------------------------