mirror of
https://github.com/google/nomulus.git
synced 2025-05-28 07:02:00 +02:00
Simplify the RyDE API
Second step of RDE encoding refactoring. Creates a single OutputStream encode RyDE files. This replaces the 5 OutputStreams that were needed before. Also removes all the factories that were injected. It's an encoding, there's no point in injecting it. Finally, removed the buffer-size configuration and replaced with a static final const value in each individual OutputStream. This doesn't yet include a decoder (InputStream). And there's still a lot of overlap between the Ryde and the Ghostryde code. Both of those are left for the next CLs. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=204898369
This commit is contained in:
parent
c4a2b5fa8d
commit
8ec2eaf39c
15 changed files with 215 additions and 345 deletions
|
@ -672,20 +672,6 @@ public final class RegistryConfig {
|
|||
return config.rde.reportUrlPrefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Size of RYDE generator buffer in bytes for each of the five layers.
|
||||
*
|
||||
* @see google.registry.rde.RydePgpCompressionOutputStream
|
||||
* @see google.registry.rde.RydePgpFileOutputStream
|
||||
* @see google.registry.rde.RydePgpSigningOutputStream
|
||||
* @see google.registry.rde.RydeTarOutputStream
|
||||
*/
|
||||
@Provides
|
||||
@Config("rdeRydeBufferSize")
|
||||
public static Integer provideRdeRydeBufferSize() {
|
||||
return 64 * 1024;
|
||||
}
|
||||
|
||||
/**
|
||||
* Maximum amount of time generating an escrow deposit for a TLD could take, before killing.
|
||||
*
|
||||
|
|
|
@ -64,11 +64,6 @@ public final class BrdaCopyAction implements Runnable {
|
|||
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
|
||||
|
||||
@Inject GcsUtils gcsUtils;
|
||||
@Inject RydePgpCompressionOutputStreamFactory pgpCompressionFactory;
|
||||
@Inject RydePgpFileOutputStreamFactory pgpFileFactory;
|
||||
@Inject RydePgpEncryptionOutputStreamFactory pgpEncryptionFactory;
|
||||
@Inject RydePgpSigningOutputStreamFactory pgpSigningFactory;
|
||||
@Inject RydeTarOutputStreamFactory tarFactory;
|
||||
@Inject @Config("brdaBucket") String brdaBucket;
|
||||
@Inject @Config("rdeBucket") String stagingBucket;
|
||||
@Inject @Parameter(RequestParameters.PARAM_TLD) String tld;
|
||||
|
@ -96,25 +91,17 @@ public final class BrdaCopyAction implements Runnable {
|
|||
|
||||
long xmlLength = readXmlLength(xmlLengthFilename);
|
||||
|
||||
logger.atInfo().log("Writing %s", rydeFile);
|
||||
byte[] signature;
|
||||
logger.atInfo().log("Writing %s and %s", rydeFile, sigFile);
|
||||
try (InputStream gcsInput = gcsUtils.openInputStream(xmlFilename);
|
||||
InputStream ghostrydeDecoder = Ghostryde.decoder(gcsInput, stagingDecryptionKey);
|
||||
OutputStream gcsOutput = gcsUtils.openOutputStream(rydeFile);
|
||||
RydePgpSigningOutputStream signLayer = pgpSigningFactory.create(gcsOutput, signingKey)) {
|
||||
try (OutputStream encryptLayer = pgpEncryptionFactory.create(signLayer, receiverKey);
|
||||
OutputStream compressLayer = pgpCompressionFactory.create(encryptLayer);
|
||||
OutputStream fileLayer = pgpFileFactory.create(compressLayer, watermark, prefix + ".tar");
|
||||
OutputStream tarLayer =
|
||||
tarFactory.create(fileLayer, xmlLength, watermark, prefix + ".xml")) {
|
||||
ByteStreams.copy(ghostrydeDecoder, tarLayer);
|
||||
}
|
||||
signature = signLayer.getSignature();
|
||||
}
|
||||
|
||||
logger.atInfo().log("Writing %s", sigFile);
|
||||
try (OutputStream gcsOutput = gcsUtils.openOutputStream(sigFile)) {
|
||||
gcsOutput.write(signature);
|
||||
OutputStream rydeOut = gcsUtils.openOutputStream(rydeFile);
|
||||
OutputStream sigOut = gcsUtils.openOutputStream(sigFile);
|
||||
RydeEncoder rydeEncoder = new RydeEncoder.Builder()
|
||||
.setRydeOutput(rydeOut, receiverKey)
|
||||
.setSignatureOutput(sigOut, signingKey)
|
||||
.setFileMetadata(prefix, xmlLength, watermark)
|
||||
.build()) {
|
||||
ByteStreams.copy(ghostrydeDecoder, rydeEncoder);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -56,6 +56,7 @@ import google.registry.util.Retrier;
|
|||
import google.registry.util.TaskQueueUtils;
|
||||
import google.registry.util.TeeOutputStream;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
@ -103,11 +104,6 @@ public final class RdeUploadAction implements Runnable, EscrowTask {
|
|||
|
||||
@Inject JSchSshSessionFactory jschSshSessionFactory;
|
||||
@Inject Response response;
|
||||
@Inject RydePgpCompressionOutputStreamFactory pgpCompressionFactory;
|
||||
@Inject RydePgpEncryptionOutputStreamFactory pgpEncryptionFactory;
|
||||
@Inject RydePgpFileOutputStreamFactory pgpFileFactory;
|
||||
@Inject RydePgpSigningOutputStreamFactory pgpSigningFactory;
|
||||
@Inject RydeTarOutputStreamFactory tarFactory;
|
||||
@Inject SftpProgressMonitor sftpProgressMonitor;
|
||||
@Inject TaskQueueUtils taskQueueUtils;
|
||||
@Inject Retrier retrier;
|
||||
|
@ -214,28 +210,27 @@ public final class RdeUploadAction implements Runnable, EscrowTask {
|
|||
InputStream ghostrydeDecoder = Ghostryde.decoder(gcsInput, stagingDecryptionKey)) {
|
||||
try (JSchSshSession session = jschSshSessionFactory.create(lazyJsch.get(), uploadUrl);
|
||||
JSchSftpChannel ftpChan = session.openSftpChannel()) {
|
||||
byte[] signature;
|
||||
ByteArrayOutputStream sigOut = new ByteArrayOutputStream();
|
||||
String rydeFilename = name + ".ryde";
|
||||
GcsFilename rydeGcsFilename = new GcsFilename(bucket, rydeFilename);
|
||||
try (OutputStream ftpOutput =
|
||||
ftpChan.get().put(rydeFilename, sftpProgressMonitor, OVERWRITE);
|
||||
OutputStream gcsOutput = gcsUtils.openOutputStream(rydeGcsFilename);
|
||||
TeeOutputStream teeOutput = new TeeOutputStream(asList(ftpOutput, gcsOutput));
|
||||
RydePgpSigningOutputStream signer = pgpSigningFactory.create(teeOutput, signingKey)) {
|
||||
try (OutputStream encryptLayer = pgpEncryptionFactory.create(signer, receiverKey);
|
||||
OutputStream kompressor = pgpCompressionFactory.create(encryptLayer);
|
||||
OutputStream fileLayer = pgpFileFactory.create(kompressor, watermark, name + ".tar");
|
||||
OutputStream tarLayer =
|
||||
tarFactory.create(fileLayer, xmlLength, watermark, name + ".xml")) {
|
||||
ByteStreams.copy(ghostrydeDecoder, tarLayer);
|
||||
RydeEncoder rydeEncoder =
|
||||
new RydeEncoder.Builder()
|
||||
.setRydeOutput(teeOutput, receiverKey)
|
||||
.setSignatureOutput(sigOut, signingKey)
|
||||
.setFileMetadata(name, xmlLength, watermark)
|
||||
.build()) {
|
||||
long bytesCopied = ByteStreams.copy(ghostrydeDecoder, rydeEncoder);
|
||||
logger.atInfo().log("uploaded %,d bytes: %s", bytesCopied, rydeFilename);
|
||||
}
|
||||
signature = signer.getSignature();
|
||||
logger.atInfo().log("uploaded %,d bytes: %s.ryde", signer.getBytesWritten(), name);
|
||||
}
|
||||
String sigFilename = name + ".sig";
|
||||
byte[] signature = sigOut.toByteArray();
|
||||
gcsUtils.createFromBytes(new GcsFilename(bucket, sigFilename), signature);
|
||||
ftpChan.get().put(new ByteArrayInputStream(signature), sigFilename);
|
||||
logger.atInfo().log("uploaded %,d bytes: %s.sig", signature.length, name);
|
||||
logger.atInfo().log("uploaded %,d bytes: %s", signature.length, sigFilename);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
153
java/google/registry/rde/RydeEncoder.java
Normal file
153
java/google/registry/rde/RydeEncoder.java
Normal file
|
@ -0,0 +1,153 @@
|
|||
// 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 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.
|
||||
*
|
||||
* <p>The RyDE format has 2 files:
|
||||
*
|
||||
* <ul>
|
||||
* <li>the "data" file, encoded in data -> tar -> PgpFile -> compression -> encryption
|
||||
* <li>the signature of the resulting file
|
||||
* </ul>
|
||||
*
|
||||
* <p>Hence, the encoder needs to receive 2 OutputStreams - one for the data and one for the
|
||||
* signature.
|
||||
*
|
||||
* <p>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<PGPPublicKey> receiverKeys) {
|
||||
super(null);
|
||||
this.sigOutput = sigOutput;
|
||||
signer = closer.register(new RydePgpSigningOutputStream(checkNotNull(rydeOutput), signingKey));
|
||||
encryptLayer = closer.register(new RydePgpEncryptionOutputStream(signer, receiverKeys));
|
||||
kompressor = closer.register(new RydePgpCompressionOutputStream(encryptLayer));
|
||||
fileLayer =
|
||||
closer.register(new RydePgpFileOutputStream(kompressor, modified, filenamePrefix + ".tar"));
|
||||
tarLayer =
|
||||
closer.register(
|
||||
new RydeTarOutputStream(fileLayer, dataLength, modified, filenamePrefix + ".xml"));
|
||||
this.out = tarLayer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Call the underlying 3 input write.
|
||||
*
|
||||
* <p>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<PGPPublicKey> receiverKeys;
|
||||
|
||||
/** Sets the OutputStream for the Ryde-encoded data, and the keys used for the encryption. */
|
||||
public Builder setRydeOutput(
|
||||
OutputStream rydeOutput, PGPPublicKey receiverKey, PGPPublicKey... moreReceiverKeys) {
|
||||
this.rydeOutput = rydeOutput;
|
||||
this.receiverKeys =
|
||||
new ImmutableList.Builder<PGPPublicKey>().add(receiverKey).add(moreReceiverKeys).build();
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Sets the OutputStream for the signature, and the key used to sign. */
|
||||
public Builder setSignatureOutput(OutputStream sigOutput, PGPKeyPair signingKey) {
|
||||
this.sigOutput = sigOutput;
|
||||
this.signingKey = signingKey;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Sets the information about the unencoded data that will follow. */
|
||||
public Builder setFileMetadata(String filenamePrefix, long dataLength, DateTime modified) {
|
||||
this.filenamePrefix = filenamePrefix;
|
||||
this.dataLength = dataLength;
|
||||
this.modified = modified;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Returns the built {@link RydeEncoder}. */
|
||||
public RydeEncoder build() {
|
||||
return new RydeEncoder(
|
||||
checkNotNull(rydeOutput, "Must call 'setRydeOutput'"),
|
||||
checkNotNull(sigOutput, "Must call 'setSignatureOutput'"),
|
||||
checkNotNull(dataLength, "Must call 'setFileMetadata'"),
|
||||
checkNotNull(filenamePrefix, "Must call 'setFileMetadata'"),
|
||||
checkNotNull(modified, "Must call 'setFileMetadata'"),
|
||||
checkNotNull(signingKey, "Must call 'setSignatureOutput'"),
|
||||
checkNotNull(receiverKeys, "Must call 'setRydeOutput'"));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -16,9 +16,6 @@ package google.registry.rde;
|
|||
|
||||
import static org.bouncycastle.bcpg.CompressionAlgorithmTags.ZIP;
|
||||
|
||||
import com.google.auto.factory.AutoFactory;
|
||||
import com.google.auto.factory.Provided;
|
||||
import google.registry.config.RegistryConfig.Config;
|
||||
import google.registry.util.ImprovedOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
@ -31,9 +28,10 @@ import org.bouncycastle.openpgp.PGPException;
|
|||
*
|
||||
* <p>This uses the ZIP compression algorithm per the ICANN escrow specification.
|
||||
*/
|
||||
@AutoFactory(allowSubclasses = true)
|
||||
public class RydePgpCompressionOutputStream extends ImprovedOutputStream {
|
||||
|
||||
private static final int BUFFER_SIZE = 64 * 1024;
|
||||
|
||||
/**
|
||||
* Creates a new instance that compresses data.
|
||||
*
|
||||
|
@ -41,9 +39,8 @@ public class RydePgpCompressionOutputStream extends ImprovedOutputStream {
|
|||
* @throws RuntimeException to rethrow {@link PGPException} and {@link IOException}
|
||||
*/
|
||||
public RydePgpCompressionOutputStream(
|
||||
@Provided @Config("rdeRydeBufferSize") Integer bufferSize,
|
||||
@WillNotClose OutputStream os) {
|
||||
super("RydePgpCompressionOutputStream", createDelegate(bufferSize, os));
|
||||
super("RydePgpCompressionOutputStream", createDelegate(BUFFER_SIZE, os));
|
||||
}
|
||||
|
||||
private static OutputStream createDelegate(int bufferSize, OutputStream os) {
|
||||
|
|
|
@ -14,18 +14,17 @@
|
|||
|
||||
package google.registry.rde;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static org.bouncycastle.bcpg.SymmetricKeyAlgorithmTags.AES_128;
|
||||
import static org.bouncycastle.jce.provider.BouncyCastleProvider.PROVIDER_NAME;
|
||||
|
||||
import com.google.auto.factory.AutoFactory;
|
||||
import com.google.auto.factory.Provided;
|
||||
import google.registry.config.RegistryConfig.Config;
|
||||
import google.registry.util.ImprovedOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.ProviderException;
|
||||
import java.security.SecureRandom;
|
||||
import java.util.Collection;
|
||||
import javax.annotation.WillNotClose;
|
||||
import org.bouncycastle.openpgp.PGPEncryptedDataGenerator;
|
||||
import org.bouncycastle.openpgp.PGPException;
|
||||
|
@ -53,9 +52,10 @@ import org.bouncycastle.openpgp.operator.jcajce.JcePublicKeyKeyEncryptionMethodG
|
|||
* @see <a href="http://tools.ietf.org/html/rfc4880">RFC 4880 (OpenPGP Message Format)</a>
|
||||
* @see <a href="http://en.wikipedia.org/wiki/Advanced_Encryption_Standard">AES (Wikipedia)</a>
|
||||
*/
|
||||
@AutoFactory(allowSubclasses = true)
|
||||
public class RydePgpEncryptionOutputStream extends ImprovedOutputStream {
|
||||
|
||||
private static final int BUFFER_SIZE = 64 * 1024;
|
||||
|
||||
/**
|
||||
* The symmetric encryption algorithm to use. Do not change this value without checking the
|
||||
* RFCs to make sure the encryption algorithm and strength combination is allowed.
|
||||
|
@ -92,22 +92,23 @@ public class RydePgpEncryptionOutputStream extends ImprovedOutputStream {
|
|||
* @throws RuntimeException to rethrow {@link PGPException} and {@link IOException}
|
||||
*/
|
||||
public RydePgpEncryptionOutputStream(
|
||||
@Provided @Config("rdeRydeBufferSize") Integer bufferSize,
|
||||
@WillNotClose OutputStream os,
|
||||
PGPPublicKey receiverKey) {
|
||||
super("RydePgpEncryptionOutputStream", createDelegate(bufferSize, os, receiverKey));
|
||||
Collection<PGPPublicKey> receiverKeys) {
|
||||
super("RydePgpEncryptionOutputStream", createDelegate(os, receiverKeys));
|
||||
}
|
||||
|
||||
private static
|
||||
OutputStream createDelegate(int bufferSize, OutputStream os, PGPPublicKey receiverKey) {
|
||||
private static OutputStream createDelegate(
|
||||
OutputStream os, Collection<PGPPublicKey> receiverKeys) {
|
||||
try {
|
||||
PGPEncryptedDataGenerator encryptor = new PGPEncryptedDataGenerator(
|
||||
new JcePGPDataEncryptorBuilder(CIPHER)
|
||||
.setWithIntegrityPacket(USE_INTEGRITY_PACKET)
|
||||
.setSecureRandom(SecureRandom.getInstance(RANDOM_SOURCE))
|
||||
.setProvider(PROVIDER_NAME));
|
||||
encryptor.addMethod(new JcePublicKeyKeyEncryptionMethodGenerator(receiverKey));
|
||||
return encryptor.open(os, new byte[bufferSize]);
|
||||
checkArgument(!receiverKeys.isEmpty(), "Must give at least one receiver key");
|
||||
receiverKeys.forEach(
|
||||
key -> encryptor.addMethod(new JcePublicKeyKeyEncryptionMethodGenerator(key)));
|
||||
return encryptor.open(os, new byte[BUFFER_SIZE]);
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
throw new ProviderException(e);
|
||||
} catch (IOException | PGPException e) {
|
||||
|
|
|
@ -17,9 +17,6 @@ package google.registry.rde;
|
|||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static org.bouncycastle.openpgp.PGPLiteralData.BINARY;
|
||||
|
||||
import com.google.auto.factory.AutoFactory;
|
||||
import com.google.auto.factory.Provided;
|
||||
import google.registry.config.RegistryConfig.Config;
|
||||
import google.registry.util.ImprovedOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
@ -36,9 +33,10 @@ import org.joda.time.DateTime;
|
|||
*
|
||||
* <p>According to escrow spec, the PGP message should contain a single tar file.
|
||||
*/
|
||||
@AutoFactory(allowSubclasses = true)
|
||||
public class RydePgpFileOutputStream extends ImprovedOutputStream {
|
||||
|
||||
private static final int BUFFER_SIZE = 64 * 1024;
|
||||
|
||||
/**
|
||||
* Creates a new instance for a particular file.
|
||||
*
|
||||
|
@ -47,20 +45,19 @@ public class RydePgpFileOutputStream extends ImprovedOutputStream {
|
|||
* @throws RuntimeException to rethrow {@link IOException}
|
||||
*/
|
||||
public RydePgpFileOutputStream(
|
||||
@Provided @Config("rdeRydeBufferSize") Integer bufferSize,
|
||||
@WillNotClose OutputStream os,
|
||||
DateTime modified,
|
||||
String filename) {
|
||||
super("RydePgpFileOutputStream", createDelegate(bufferSize, os, modified, filename));
|
||||
super("RydePgpFileOutputStream", createDelegate(os, modified, filename));
|
||||
}
|
||||
|
||||
private static OutputStream
|
||||
createDelegate(int bufferSize, OutputStream os, DateTime modified, String filename) {
|
||||
createDelegate(OutputStream os, DateTime modified, String filename) {
|
||||
try {
|
||||
checkArgument(filename.endsWith(".tar"),
|
||||
"Ryde PGP message should contain a tar file.");
|
||||
return new PGPLiteralDataGenerator().open(
|
||||
os, BINARY, filename, modified.toDate(), new byte[bufferSize]);
|
||||
os, BINARY, filename, modified.toDate(), new byte[BUFFER_SIZE]);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
|
|
@ -18,7 +18,6 @@ import static org.bouncycastle.bcpg.HashAlgorithmTags.SHA256;
|
|||
import static org.bouncycastle.bcpg.PublicKeyAlgorithmTags.RSA_GENERAL;
|
||||
import static org.bouncycastle.openpgp.PGPSignature.BINARY_DOCUMENT;
|
||||
|
||||
import com.google.auto.factory.AutoFactory;
|
||||
import google.registry.util.ImprovedOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
@ -40,7 +39,6 @@ import org.bouncycastle.openpgp.operator.bc.BcPGPContentSignerBuilder;
|
|||
* who receive a deposit to check the signature against our public key so they can know the
|
||||
* data hasn't been forged.
|
||||
*/
|
||||
@AutoFactory(allowSubclasses = true)
|
||||
public class RydePgpSigningOutputStream extends ImprovedOutputStream {
|
||||
|
||||
private final PGPSignatureGenerator signer;
|
||||
|
|
|
@ -16,7 +16,6 @@ package google.registry.rde;
|
|||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
|
||||
import com.google.auto.factory.AutoFactory;
|
||||
import google.registry.util.ImprovedOutputStream;
|
||||
import google.registry.util.PosixTarHeader;
|
||||
import java.io.IOException;
|
||||
|
@ -27,7 +26,6 @@ import org.joda.time.DateTime;
|
|||
/**
|
||||
* Single-file POSIX tar archive creator that wraps an {@link OutputStream}.
|
||||
*/
|
||||
@AutoFactory(allowSubclasses = true)
|
||||
public class RydeTarOutputStream extends ImprovedOutputStream {
|
||||
|
||||
private final long expectedSize;
|
||||
|
|
|
@ -20,16 +20,7 @@ import com.google.common.io.ByteStreams;
|
|||
import google.registry.keyring.api.KeyModule.Key;
|
||||
import google.registry.model.rde.RdeNamingUtils;
|
||||
import google.registry.rde.RdeUtil;
|
||||
import google.registry.rde.RydePgpCompressionOutputStream;
|
||||
import google.registry.rde.RydePgpCompressionOutputStreamFactory;
|
||||
import google.registry.rde.RydePgpEncryptionOutputStream;
|
||||
import google.registry.rde.RydePgpEncryptionOutputStreamFactory;
|
||||
import google.registry.rde.RydePgpFileOutputStream;
|
||||
import google.registry.rde.RydePgpFileOutputStreamFactory;
|
||||
import google.registry.rde.RydePgpSigningOutputStream;
|
||||
import google.registry.rde.RydePgpSigningOutputStreamFactory;
|
||||
import google.registry.rde.RydeTarOutputStream;
|
||||
import google.registry.rde.RydeTarOutputStreamFactory;
|
||||
import google.registry.rde.RydeEncoder;
|
||||
import google.registry.xml.XmlException;
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.IOException;
|
||||
|
@ -40,7 +31,6 @@ import java.nio.file.Path;
|
|||
import javax.inject.Inject;
|
||||
import javax.inject.Provider;
|
||||
import org.bouncycastle.bcpg.ArmoredOutputStream;
|
||||
import org.bouncycastle.openpgp.PGPException;
|
||||
import org.bouncycastle.openpgp.PGPKeyPair;
|
||||
import org.bouncycastle.openpgp.PGPPublicKey;
|
||||
import org.joda.time.DateTime;
|
||||
|
@ -50,18 +40,13 @@ final class EscrowDepositEncryptor {
|
|||
|
||||
private static final int PEEK_BUFFER_SIZE = 64 * 1024;
|
||||
|
||||
@Inject RydePgpCompressionOutputStreamFactory pgpCompressionFactory;
|
||||
@Inject RydePgpEncryptionOutputStreamFactory pgpEncryptionFactory;
|
||||
@Inject RydePgpFileOutputStreamFactory pgpFileFactory;
|
||||
@Inject RydePgpSigningOutputStreamFactory pgpSigningFactory;
|
||||
@Inject RydeTarOutputStreamFactory tarFactory;
|
||||
@Inject @Key("rdeSigningKey") Provider<PGPKeyPair> rdeSigningKey;
|
||||
@Inject @Key("rdeReceiverKey") Provider<PGPPublicKey> rdeReceiverKey;
|
||||
@Inject EscrowDepositEncryptor() {}
|
||||
|
||||
/** Creates a {@code .ryde} and {@code .sig} file, provided an XML deposit file. */
|
||||
void encrypt(String tld, Path xmlFile, Path outdir)
|
||||
throws IOException, PGPException, XmlException {
|
||||
throws IOException, XmlException {
|
||||
try (InputStream xmlFileInput = Files.newInputStream(xmlFile);
|
||||
BufferedInputStream xmlInput = new BufferedInputStream(xmlFileInput, PEEK_BUFFER_SIZE)) {
|
||||
DateTime watermark = RdeUtil.peekWatermark(xmlInput);
|
||||
|
@ -71,23 +56,17 @@ final class EscrowDepositEncryptor {
|
|||
Path pubPath = outdir.resolve(tld + ".pub");
|
||||
PGPKeyPair signingKey = rdeSigningKey.get();
|
||||
try (OutputStream rydeOutput = Files.newOutputStream(rydePath);
|
||||
RydePgpSigningOutputStream signLayer =
|
||||
pgpSigningFactory.create(rydeOutput, signingKey)) {
|
||||
try (RydePgpEncryptionOutputStream encryptLayer =
|
||||
pgpEncryptionFactory.create(signLayer, rdeReceiverKey.get());
|
||||
RydePgpCompressionOutputStream compressLayer =
|
||||
pgpCompressionFactory.create(encryptLayer);
|
||||
RydePgpFileOutputStream fileLayer =
|
||||
pgpFileFactory.create(compressLayer, watermark, name + ".tar");
|
||||
RydeTarOutputStream tarLayer =
|
||||
tarFactory.create(fileLayer, Files.size(xmlFile), watermark, name + ".xml")) {
|
||||
ByteStreams.copy(xmlInput, tarLayer);
|
||||
}
|
||||
Files.write(sigPath, signLayer.getSignature());
|
||||
try (OutputStream pubOutput = Files.newOutputStream(pubPath);
|
||||
ArmoredOutputStream ascOutput = new ArmoredOutputStream(pubOutput)) {
|
||||
signingKey.getPublicKey().encode(ascOutput);
|
||||
}
|
||||
OutputStream sigOutput = Files.newOutputStream(sigPath);
|
||||
RydeEncoder rydeEncoder = new RydeEncoder.Builder()
|
||||
.setRydeOutput(rydeOutput, rdeReceiverKey.get())
|
||||
.setSignatureOutput(sigOutput, signingKey)
|
||||
.setFileMetadata(name, Files.size(xmlFile), watermark)
|
||||
.build()) {
|
||||
ByteStreams.copy(xmlInput, rydeEncoder);
|
||||
}
|
||||
try (OutputStream pubOutput = Files.newOutputStream(pubPath);
|
||||
ArmoredOutputStream ascOutput = new ArmoredOutputStream(pubOutput)) {
|
||||
signingKey.getPublicKey().encode(ascOutput);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue