// Copyright 2018 The Nomulus Authors. All Rights Reserved. // // 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 google.registry.rde; import static com.google.common.base.Preconditions.checkNotNull; import static google.registry.rde.RydeCompression.openCompressor; import static google.registry.rde.RydeEncryption.RYDE_USE_INTEGRITY_PACKET; import static google.registry.rde.RydeEncryption.openEncryptor; import static google.registry.rde.RydeFileEncoding.openPgpFileWriter; import static google.registry.rde.RydeTar.openTarWriter; import com.google.common.collect.ImmutableList; import com.google.common.io.Closer; import java.io.FilterOutputStream; import java.io.IOException; import java.io.OutputStream; import java.util.Collection; import javax.annotation.concurrent.NotThreadSafe; import org.bouncycastle.openpgp.PGPException; import org.bouncycastle.openpgp.PGPKeyPair; import org.bouncycastle.openpgp.PGPPublicKey; import org.joda.time.DateTime; /** * Stream that performs the full RyDE encryption. * *
The RyDE format has 2 files: * *
Hence, the encoder needs to receive 2 OutputStreams - one for the data and one for the * signature. * *
Because of the external tar file encoding - the encoder must know the total length of the data
* from the start. This is a bit annoying, but necessary.
*/
@NotThreadSafe
public final class RydeEncoder extends FilterOutputStream {
private final OutputStream sigOutput;
private final RydePgpSigningOutputStream signer;
private final OutputStream encryptLayer;
private final OutputStream kompressor;
private final OutputStream fileLayer;
private final OutputStream tarLayer;
// We use a Closer to handle the stream .close, to make sure it's done correctly.
private final Closer closer = Closer.create();
private boolean isClosed = false;
private RydeEncoder(
OutputStream rydeOutput,
OutputStream sigOutput,
long dataLength,
String filenamePrefix,
DateTime modified,
PGPKeyPair signingKey,
Collection FilterInputStream implements the 3 input write using a for loop over the single-byte write.
* For efficiency reasons, we want it to use the 3 input write instead.
*/
@Override
public void write(byte[] b, int off, int len) throws IOException {
out.write(b, off, len);
}
@Override
public void close() throws IOException {
if (isClosed) {
return;
}
// Close all the streams we opened
closer.close();
isClosed = true;
try {
sigOutput.write(signer.getSignature());
} catch (PGPException e) {
throw new RuntimeException("Failed to generate signature", e);
}
}
/** Builder for {@link RydeEncoder}. */
public static class Builder {
OutputStream rydeOutput;
OutputStream sigOutput;
Long dataLength;
String filenamePrefix;
DateTime modified;
PGPKeyPair signingKey;
ImmutableList