All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.exceptionfactory.jagged.scrypt.ScryptRecipientStanzaWriter Maven / Gradle / Ivy

/*
 * Copyright 2023 Jagged Contributors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.exceptionfactory.jagged.scrypt;

import com.exceptionfactory.jagged.FileKey;
import com.exceptionfactory.jagged.RecipientStanza;
import com.exceptionfactory.jagged.RecipientStanzaWriter;
import com.exceptionfactory.jagged.framework.crypto.CipherKey;
import com.exceptionfactory.jagged.framework.crypto.EncryptedFileKey;
import com.exceptionfactory.jagged.framework.crypto.FileKeyEncryptor;
import com.exceptionfactory.jagged.framework.codec.CanonicalBase64;

import java.security.GeneralSecurityException;
import java.security.SecureRandom;
import java.util.Collections;
import java.util.Objects;

/**
 * Standard age-encryption Recipient Stanza Writer implementation using scrypt password-based key derivation as described in RFC 7914
 */
class ScryptRecipientStanzaWriter implements RecipientStanzaWriter {
    private static final int SALT_LENGTH = 16;

    private static final SecureRandom SECURE_RANDOM = new SecureRandom();

    private static final CanonicalBase64.Encoder ENCODER = CanonicalBase64.getEncoder();

    private final DerivedWrapKeyProducer derivedWrapKeyProducer;

    private final int workFactor;

    private final FileKeyEncryptor fileKeyEncryptor;

    /**
     * scrypt Recipient Stanza Writer with wrap key producer containing passphrase and work factor for key derivation
     *
     * @param derivedWrapKeyProducer Derived Wrap Key Producer based on supplied passphrase
     * @param workFactor scrypt work factor
     * @param fileKeyEncryptor File Key Encryptor
     */
    ScryptRecipientStanzaWriter(final DerivedWrapKeyProducer derivedWrapKeyProducer, final int workFactor, final FileKeyEncryptor fileKeyEncryptor) {
        this.derivedWrapKeyProducer = Objects.requireNonNull(derivedWrapKeyProducer, "Wrap Key Producer required");
        this.workFactor = workFactor;
        this.fileKeyEncryptor = Objects.requireNonNull(fileKeyEncryptor, "File Key Encryptor required");
    }

    /**
     * Get Recipient Stanzas containing one scrypt Recipient Stanza with the encrypted File Key
     *
     * @param fileKey File Key to be encrypted
     * @return Singleton List of scrypt Recipient Stanza with encrypted File Key
     * @throws GeneralSecurityException Thrown key derivation or encryption failures
     */
    @Override
    public Iterable getRecipientStanzas(final FileKey fileKey) throws GeneralSecurityException {
        Objects.requireNonNull(fileKey, "File Key required");

        final byte[] salt = getSalt();
        final CipherKey wrapKey = derivedWrapKeyProducer.getWrapKey(salt, workFactor);
        final EncryptedFileKey encryptedFileKey = fileKeyEncryptor.getEncryptedFileKey(fileKey, wrapKey);
        final byte[] encryptedFileKeyEncoded = encryptedFileKey.getEncoded();

        final String saltEncoded = ENCODER.encodeToString(salt);
        final RecipientStanza recipientStanza = new ScryptRecipientStanza(saltEncoded, workFactor, encryptedFileKeyEncoded);
        return Collections.singletonList(recipientStanza);
    }

    private byte[] getSalt() {
        final byte[] salt = new byte[SALT_LENGTH];
        SECURE_RANDOM.nextBytes(salt);
        return salt;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy