Use uint64 for backups.proto object length

This commit is contained in:
Ravi Khadiwala 2026-06-16 12:53:28 -05:00 committed by Jon Chambers
parent 024fa9ce5f
commit 06519ce9d1
6 changed files with 15 additions and 26 deletions

View File

@ -86,7 +86,7 @@ public class Cdn3RemoteStorageManager implements RemoteStorageManager {
public CompletionStage<Void> copy(
final int sourceCdn,
final String sourceKey,
final int expectedSourceLength,
final long expectedSourceLength,
final MediaEncryptionParameters encryptionParameters,
final String destinationKey) {
final String sourceScheme = this.sourceSchemes.get(sourceCdn);
@ -132,10 +132,10 @@ public class Cdn3RemoteStorageManager implements RemoteStorageManager {
*/
record Cdn3CopyRequest(
String encryptionKey, String hmacKey,
SourceDescriptor source, int expectedSourceLength,
SourceDescriptor source, long expectedSourceLength,
String dst) {
Cdn3CopyRequest(MediaEncryptionParameters parameters, SourceDescriptor source, int expectedSourceLength,
Cdn3CopyRequest(MediaEncryptionParameters parameters, SourceDescriptor source, long expectedSourceLength,
String dst) {
this(Base64.getEncoder().encodeToString(parameters.aesEncryptionKey().getEncoded()),
Base64.getEncoder().encodeToString(parameters.hmacSHA256Key().getEncoded()),

View File

@ -18,7 +18,7 @@ import com.google.common.annotations.VisibleForTesting;
public record CopyParameters(
int sourceCdn,
String sourceKey,
int sourceLength,
long sourceLength,
MediaEncryptionParameters encryptionParameters,
byte[] destinationMediaId) {
@ -35,16 +35,17 @@ public record CopyParameters(
///
/// @return the size, in bytes, of the ciphertext of a media object with the given `inputSize`
@VisibleForTesting
static long destinationObjectSize(final int inputSize) {
static long destinationObjectSize(final long inputSize) {
if (inputSize < 0) {
throw new IllegalArgumentException("Size must be non-negative, but was " + inputSize);
}
// AES-256 has 16-byte block size, and always adds a block if the plaintext is a multiple of the block size
final long numBlocks = ((long) inputSize + 16) / 16;
final long numBlocks = Math.addExact(inputSize, 16L) / 16;
final long cipherTextLength = Math.multiplyExact(numBlocks, 16);
// 16-byte IV will be generated and prepended to the ciphertext
// 16-byte IV will be generated and prepended to the ciphertext.
// IV + AES-256 encrypted data + HmacSHA256
return 16 + (numBlocks * 16) + 32;
return Math.addExact(cipherTextLength, 16L + 32);
}
}

View File

@ -35,7 +35,7 @@ public interface RemoteStorageManager {
CompletionStage<Void> copy(
int sourceCdn,
String sourceKey,
int expectedSourceLength,
long expectedSourceLength,
MediaEncryptionParameters encryptionParameters,
String dstKey);

View File

@ -224,8 +224,7 @@ public class BackupsAnonymousGrpcService extends SimpleBackupsAnonymousGrpc.Back
copyQuota = backupManager.getCopyQuota(backupUser,
request.getItemsList().stream().map(item -> new CopyParameters(
item.getSourceAttachmentCdn(), item.getSourceKey(),
// uint32 in proto, make sure it fits in a signed int
fromUnsignedExact(item.getObjectLength()),
item.getObjectLength(),
new MediaEncryptionParameters(item.getEncryptionKey().toByteArray(), item.getHmacKey().toByteArray()),
item.getMediaId().toByteArray())).toList(), maxAttachmentSize);
} catch (BackupFailedZkAuthenticationException e) {
@ -351,17 +350,6 @@ public class BackupsAnonymousGrpcService extends SimpleBackupsAnonymousGrpc.Back
}
}
/**
* Convert an int from a proto uint32 to a signed positive integer, throwing if the value exceeds
* {@link Integer#MAX_VALUE}. To convert to a long, see {@link Integer#toUnsignedLong(int)}
*/
private static int fromUnsignedExact(final int i) {
if (i < 0) {
throw GrpcExceptions.invalidArguments("integer length too large");
}
return i;
}
private interface Deserializer<T> {
T deserialize(byte[] bytes) throws InvalidInputException, InvalidKeyException;

View File

@ -410,7 +410,7 @@ message CopyMediaItem {
// The length of the source attachment before the encryption applied by the
// copy operation
uint32 object_length = 3;
uint64 object_length = 3;
// media_id to copy on to the backup CDN
bytes media_id = 4 [(require.exactlySize) = 15];

View File

@ -525,11 +525,11 @@ public class BackupManagerTest {
when(tusCredentialGenerator.generateUpload(any(), anyLong()))
.thenReturn(new BackupUploadDescriptor(3, "", Collections.emptyMap(), ""));
when(remoteStorageManager.copy(eq(3), eq("success"), eq(100), any(), any()))
when(remoteStorageManager.copy(eq(3), eq("success"), eq(100L), any(), any()))
.thenReturn(CompletableFuture.completedFuture(null));
when(remoteStorageManager.copy(eq(3), eq("missing"), eq(200), any(), any()))
when(remoteStorageManager.copy(eq(3), eq("missing"), eq(200L), any(), any()))
.thenReturn(CompletableFuture.failedFuture(new SourceObjectNotFoundException()));
when(remoteStorageManager.copy(eq(3), eq("badlength"), eq(300), any(), any()))
when(remoteStorageManager.copy(eq(3), eq("badlength"), eq(300L), any(), any()))
.thenReturn(CompletableFuture.failedFuture(new InvalidLengthException("")));
final List<CopyResult> results = backupManager