You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@iceberg.apache.org by GitBox <gi...@apache.org> on 2022/08/04 06:32:22 UTC

[GitHub] [iceberg] ggershinsky opened a new pull request, #5432: AES GCM Stream Spec

ggershinsky opened a new pull request, #5432:
URL: https://github.com/apache/iceberg/pull/5432

   @rdblue @RussellSpitzer @jackye1995 


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscribe@iceberg.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: issues-unsubscribe@iceberg.apache.org
For additional commands, e-mail: issues-help@iceberg.apache.org


[GitHub] [iceberg] ggershinsky commented on a diff in pull request #5432: AES GCM Stream Spec

Posted by GitBox <gi...@apache.org>.
ggershinsky commented on code in PR #5432:
URL: https://github.com/apache/iceberg/pull/5432#discussion_r963353438


##########
format/gcm-stream-spec.md:
##########
@@ -0,0 +1,87 @@
+---
+title: "AES GCM Stream Spec"
+url: gcm-stream-spec
+toc: true
+disableSidebar: true
+---
+<!--
+ - Licensed to the Apache Software Foundation (ASF) under one or more
+ - contributor license agreements.  See the NOTICE file distributed with
+ - this work for additional information regarding copyright ownership.
+ - The ASF licenses this file to You 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.
+ -->
+
+# AES GCM Stream (AGS) file format extension
+
+## Background and Motivation
+
+Iceberg supports a number of data file formats. Two of these formats (Parquet and ORC) have built-in encryption capabilities, that allow to protect sensitive information in the data files. However, besides the data files, Iceberg tables also have metadata files, that keep sensitive information too (e.g., min/max values in manifest files, or bloom filter bitsets in puffin files). Metadata file formats (AVRO, JSON, Puffin) don't have encryption support.
+
+Moreover, with the exception of Parquet, no Iceberg data or metadata file format supports integrity verification, required for end-to-end tamper proofing of Iceberg tables.
+
+This document specifies details of a simple file format extension that adds encryption and tamper-proofing to any existing file format.
+
+## Goals
+
+* Metadata encryption: enable encryption of manifests, manifest lists, snapshots and stats.
+* Avro data encryption: enable encryption of data files in tables that use the Avro format.

Review Comment:
   yep, splitting should be possible - if it is based on the standard file/stream API, used in Iceberg (file `getLength`; stream `skip`, `seek`, `getPos`).
   I'll add it as an explicit goal.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscribe@iceberg.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: issues-unsubscribe@iceberg.apache.org
For additional commands, e-mail: issues-help@iceberg.apache.org


[GitHub] [iceberg] rdblue commented on a diff in pull request #5432: AES GCM Stream Spec

Posted by GitBox <gi...@apache.org>.
rdblue commented on code in PR #5432:
URL: https://github.com/apache/iceberg/pull/5432#discussion_r950908532


##########
format/gcm-stream-spec.md:
##########
@@ -0,0 +1,87 @@
+---
+title: "AES GCM Stream Spec"
+url: gcm-stream-spec
+toc: true
+disableSidebar: true
+---
+<!--
+ - Licensed to the Apache Software Foundation (ASF) under one or more
+ - contributor license agreements.  See the NOTICE file distributed with
+ - this work for additional information regarding copyright ownership.
+ - The ASF licenses this file to You 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.
+ -->
+
+# AES GCM Stream (AGS) file format extension
+
+## Background and Motivation
+
+Iceberg supports a number of data file formats. Two of these formats (Parquet and ORC) have built-in encryption capabilities, that allow to protect sensitive information in the data files. However, besides the data files, Iceberg tables also have metadata files, that keep sensitive information too (e.g., min/max values in manifest files, or bloom filter bitsets in puffin files). Metadata file formats (AVRO, JSON, Puffin) don't have encryption support.
+
+Moreover, with the exception of Parquet, no Iceberg data or metadata file format supports integrity verification, required for end-to-end tamper proofing of Iceberg tables.
+
+This document specifies details of a simple file format extension that adds encryption and tamper-proofing to any existing file format.

Review Comment:
   I think this should be more clear that the proposal is to encrypt an entire stream, which will prevent skipping in the underlying file.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscribe@iceberg.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: issues-unsubscribe@iceberg.apache.org
For additional commands, e-mail: issues-help@iceberg.apache.org


[GitHub] [iceberg] ggershinsky commented on pull request #5432: AES GCM Stream Spec

Posted by GitBox <gi...@apache.org>.
ggershinsky commented on PR #5432:
URL: https://github.com/apache/iceberg/pull/5432#issuecomment-1308656393

   All suggestions SGTM, I'll update the doc accordingly.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscribe@iceberg.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: issues-unsubscribe@iceberg.apache.org
For additional commands, e-mail: issues-help@iceberg.apache.org


[GitHub] [iceberg] ggershinsky commented on a diff in pull request #5432: AES GCM Stream Spec

Posted by GitBox <gi...@apache.org>.
ggershinsky commented on code in PR #5432:
URL: https://github.com/apache/iceberg/pull/5432#discussion_r963362686


##########
format/gcm-stream-spec.md:
##########
@@ -0,0 +1,87 @@
+---
+title: "AES GCM Stream Spec"
+url: gcm-stream-spec
+toc: true
+disableSidebar: true
+---
+<!--
+ - Licensed to the Apache Software Foundation (ASF) under one or more
+ - contributor license agreements.  See the NOTICE file distributed with
+ - this work for additional information regarding copyright ownership.
+ - The ASF licenses this file to You 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.
+ -->
+
+# AES GCM Stream (AGS) file format extension
+
+## Background and Motivation
+
+Iceberg supports a number of data file formats. Two of these formats (Parquet and ORC) have built-in encryption capabilities, that allow to protect sensitive information in the data files. However, besides the data files, Iceberg tables also have metadata files, that keep sensitive information too (e.g., min/max values in manifest files, or bloom filter bitsets in puffin files). Metadata file formats (AVRO, JSON, Puffin) don't have encryption support.
+
+Moreover, with the exception of Parquet, no Iceberg data or metadata file format supports integrity verification, required for end-to-end tamper proofing of Iceberg tables.
+
+This document specifies details of a simple file format extension that adds encryption and tamper-proofing to any existing file format.
+
+## Goals
+
+* Metadata encryption: enable encryption of manifests, manifest lists, snapshots and stats.
+* Avro data encryption: enable encryption of data files in tables that use the Avro format.
+* Tamper proofing of Iceberg data and metadata files.
+
+## Overview
+
+The output stream, produced by a metadata or data writer, is split into equal-size blocks (plus residue). Each block is enciphered (encrypted/signed) with a given encryption key, and stored in a file in the AGS format. Upon reading, the stored cipherblocks are verified for integrity; then decrypted and passed to metadata or data readers.
+
+## Encryption algorithm
+
+AGS uses the standard AEG GCM cipher, and supports all AES key sizes: 128, 192 and 256 bits.
+
+AES GCM is an authenticated encryption. Besides data confidentiality (encryption), it supports two levels of integrity verification (authentication): of the data (default), and of the data combined with an optional AAD (“additional authenticated data”). An AAD is a free text to be authenticated, together with the data. The structure of AGS AADs is described below.
+
+AES GCM requires a unique vector to be provided for each encrypted block. In this document, the unique input to GCM encryption is called nonce (“number used once”). AGS encryption uses the RBG-based (random bit generator) nonce construction as defined in the section 8.2.2 of the NIST SP 800-38D document. For each encrypted block, AGS generates a unique nonce with a length of 12 bytes (96 bits).
+
+## Format specification
+
+### File structure
+
+The AGS-encrypted files have the following structure
+
+```
+Magic BlockLength CipherBlock₁ CipherBlock₂ ... CipherBlockₙ
+```
+
+where
+
+- `Magic` is four bytes 0x41, 0x47, 0x53, 0x31 ("AGS1", short for: AES GCM Stream, version 1)
+- `BlockLength` is four bytes (little endian) integer keeping the length of the equal-size split blocks before encryption. The length is specified in bytes.
+- `CipherBlockᵢ` is the i-th enciphered block in the file, with the structure defined below.
+
+### Cipher Block structure
+
+Cipher blocks have the following structure
+
+| nonce | ciphertext | tag |
+|-------|------------|-----|
+
+where
+
+- `nonce` is the AES GCM nonce, with a length of 12 bytes.
+- `ciphertext` is the encrypted block. Its length is identical to the length of the block before encryption ("plaintext"). The length of all plaintext blocks, except the last, is `BlockLength` bytes. The last block keeps the data residue, with a length <= `BlockLength`.
+- `tag` is the AES GCM tag, with a length of 16 bytes.
+
+AGS encrypts all blocks by the GCM cipher, without padding. The AES GCM cipher must be implemented by a cryptographic provider according to the NIST SP 800-38D specification. In AGS, an input to the GCM cipher is an AES encryption key, a nonce, a plaintext and an AAD (described below). The output is a ciphertext with the length equal to that of plaintext, and a 16-byte authentication tag used to verify the ciphertext and AAD integrity.
+
+### Additional Authenticated Data
+
+The AES GCM cipher protects against byte replacement inside a ciphertext block - but, without an AAD, it can't prevent replacement of one ciphertext block with another (encrypted with the same key). AGS leverages AADs to protect against swapping ciphertext blocks inside a file or between files. AGS can also protect against swapping full files - for example, replacement of a metadata file with an old version. AADs are built to reflects the identity of a file and of the blocks inside the file.
+
+AGS constructs a block AAD from two components: an AAD prefix - a string provided by Iceberg for the file (with the file ID), and an AAD suffix - the block sequence number in the file, as an int in a 4-byte little-endian form. The block AAD is a direct concatenation of the prefix and suffix parts.

Review Comment:
   Technically, this spec is narrowly focused on the low level encryption stream and the tools it provides, including a file ID (aka AAD prefix) that should be supplied by the upper layers. We don't have the details yet on how it will be constructed for an Iceberg metadata tree; TBD; but once we have these details, I guess we can/should put them in a separate higher-level spec doc? E.g. a new encryption/integrity section in the Iceberg spec?



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscribe@iceberg.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: issues-unsubscribe@iceberg.apache.org
For additional commands, e-mail: issues-help@iceberg.apache.org


[GitHub] [iceberg] rdblue commented on a diff in pull request #5432: AES GCM Stream Spec

Posted by GitBox <gi...@apache.org>.
rdblue commented on code in PR #5432:
URL: https://github.com/apache/iceberg/pull/5432#discussion_r950908604


##########
format/gcm-stream-spec.md:
##########
@@ -0,0 +1,87 @@
+---
+title: "AES GCM Stream Spec"
+url: gcm-stream-spec
+toc: true
+disableSidebar: true
+---
+<!--
+ - Licensed to the Apache Software Foundation (ASF) under one or more
+ - contributor license agreements.  See the NOTICE file distributed with
+ - this work for additional information regarding copyright ownership.
+ - The ASF licenses this file to You 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.
+ -->
+
+# AES GCM Stream (AGS) file format extension
+
+## Background and Motivation
+
+Iceberg supports a number of data file formats. Two of these formats (Parquet and ORC) have built-in encryption capabilities, that allow to protect sensitive information in the data files. However, besides the data files, Iceberg tables also have metadata files, that keep sensitive information too (e.g., min/max values in manifest files, or bloom filter bitsets in puffin files). Metadata file formats (AVRO, JSON, Puffin) don't have encryption support.
+
+Moreover, with the exception of Parquet, no Iceberg data or metadata file format supports integrity verification, required for end-to-end tamper proofing of Iceberg tables.
+
+This document specifies details of a simple file format extension that adds encryption and tamper-proofing to any existing file format.
+
+## Goals
+
+* Metadata encryption: enable encryption of manifests, manifest lists, snapshots and stats.
+* Avro data encryption: enable encryption of data files in tables that use the Avro format.
+* Tamper proofing of Iceberg data and metadata files.
+
+## Overview
+
+The output stream, produced by a metadata or data writer, is split into equal-size blocks (plus residue). Each block is enciphered (encrypted/signed) with a given encryption key, and stored in a file in the AGS format. Upon reading, the stored cipherblocks are verified for integrity; then decrypted and passed to metadata or data readers.

Review Comment:
   "residue" is not defined?



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscribe@iceberg.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: issues-unsubscribe@iceberg.apache.org
For additional commands, e-mail: issues-help@iceberg.apache.org


[GitHub] [iceberg] rdblue commented on a diff in pull request #5432: AES GCM Stream Spec

Posted by GitBox <gi...@apache.org>.
rdblue commented on code in PR #5432:
URL: https://github.com/apache/iceberg/pull/5432#discussion_r950916081


##########
format/gcm-stream-spec.md:
##########
@@ -0,0 +1,87 @@
+---
+title: "AES GCM Stream Spec"
+url: gcm-stream-spec
+toc: true
+disableSidebar: true
+---
+<!--
+ - Licensed to the Apache Software Foundation (ASF) under one or more
+ - contributor license agreements.  See the NOTICE file distributed with
+ - this work for additional information regarding copyright ownership.
+ - The ASF licenses this file to You 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.
+ -->
+
+# AES GCM Stream (AGS) file format extension
+
+## Background and Motivation
+
+Iceberg supports a number of data file formats. Two of these formats (Parquet and ORC) have built-in encryption capabilities, that allow to protect sensitive information in the data files. However, besides the data files, Iceberg tables also have metadata files, that keep sensitive information too (e.g., min/max values in manifest files, or bloom filter bitsets in puffin files). Metadata file formats (AVRO, JSON, Puffin) don't have encryption support.
+
+Moreover, with the exception of Parquet, no Iceberg data or metadata file format supports integrity verification, required for end-to-end tamper proofing of Iceberg tables.
+
+This document specifies details of a simple file format extension that adds encryption and tamper-proofing to any existing file format.
+
+## Goals
+
+* Metadata encryption: enable encryption of manifests, manifest lists, snapshots and stats.
+* Avro data encryption: enable encryption of data files in tables that use the Avro format.
+* Tamper proofing of Iceberg data and metadata files.
+
+## Overview
+
+The output stream, produced by a metadata or data writer, is split into equal-size blocks (plus residue). Each block is enciphered (encrypted/signed) with a given encryption key, and stored in a file in the AGS format. Upon reading, the stored cipherblocks are verified for integrity; then decrypted and passed to metadata or data readers.
+
+## Encryption algorithm
+
+AGS uses the standard AEG GCM cipher, and supports all AES key sizes: 128, 192 and 256 bits.
+
+AES GCM is an authenticated encryption. Besides data confidentiality (encryption), it supports two levels of integrity verification (authentication): of the data (default), and of the data combined with an optional AAD (“additional authenticated data”). An AAD is a free text to be authenticated, together with the data. The structure of AGS AADs is described below.
+
+AES GCM requires a unique vector to be provided for each encrypted block. In this document, the unique input to GCM encryption is called nonce (“number used once”). AGS encryption uses the RBG-based (random bit generator) nonce construction as defined in the section 8.2.2 of the NIST SP 800-38D document. For each encrypted block, AGS generates a unique nonce with a length of 12 bytes (96 bits).
+
+## Format specification
+
+### File structure
+
+The AGS-encrypted files have the following structure
+
+```
+Magic BlockLength CipherBlock₁ CipherBlock₂ ... CipherBlockₙ
+```
+
+where
+
+- `Magic` is four bytes 0x41, 0x47, 0x53, 0x31 ("AGS1", short for: AES GCM Stream, version 1)
+- `BlockLength` is four bytes (little endian) integer keeping the length of the equal-size split blocks before encryption. The length is specified in bytes.
+- `CipherBlockᵢ` is the i-th enciphered block in the file, with the structure defined below.
+
+### Cipher Block structure
+
+Cipher blocks have the following structure
+
+| nonce | ciphertext | tag |
+|-------|------------|-----|

Review Comment:
   To be able to split formats like Avro that are splittable, we need to be able to go back and forth between offsets in the underlying data stream and in the AGS stream. I think that's possible since this has a strict format. The header structure is 8 bytes (4 magic + 4 block length) and then there is 24 bytes of overhead per CipherBlock (12 nonce + 12 tag).
   
   For any given offset in the underlying stream, we can find the block where it will be found by dividing by the block length:
   
   ```python
   def plain_block_index(plain_offset, block_length):
       return offset // block_length
   ```
   
   Then we can skip to a given block:
   
   ```python
   def cipher_block_offset(block_index, block_length):
       return 8 + block_index * (24 + block_length)
   ```
   
   But the problem is that we don't get split offsets in the underlying file, we get split offsets in the AGS stream and need to figure out where in the underlying file those translate to, so that we don't have overlapping ranges that tasks are responsible for. We have a picture like this for a block size of 1024, 3 blocks, and a last block of size 553:
   
   |  | magic | block length | nonce-1 | ciphertext-1 | tag-1 | nonce-2 | ciphertext-2 | tag-2 | nonce-3 | ciphertext-3 | tag-3 | EOF |
   | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- |
   | AGS offset | 0 | 4 | 8 | 20 (to 1043) | 1044 | 1056 | 1068 (to 2091) | 2092 | 2104 | 2116 (to 2668) | 2669 | 2681 |
   | Stream offset |  |  |  | 0 (to 1023) |  |  | 1024 (to 2047) |  |  | 2048 (to 2601) |  | 2602 |
   
   To convert an AGS offset into a stream offset, I think we need to produce the the block index and an offset in that block. Producing the block index is the opposite of the `cipher_block_offset` function:
   
   ```python
   def cipher_block_index(cipher_offset, block_length):
       if (cipher_offset < 8):
           raise ValueError()
       return (cipher_offset - 8) // (block_length + 24)
   ```
   
   Then the offset in the plaintext block can be produced by subtracting the ciphertext offset from the start of the ciphertext block and some extra accounting:
   
   ```python
   def plaintext_block_offset(cipher_offset, block_length):
       block_index = cipher_block_index(cipher_offset, block_length)
       block_start = cipher_block_offset(block_index, block_length)
       local_offset = cipher_offset - block_start
       return min(local_offset, block_length)
   ```
   
   The min with `block_length` ensures that the local block offsets never overlap. Offsets that are between the ciphertext blocks (like 1048 in tag-1 for the example above) are mapped to the end of the plaintext block. This gives us a stable way to recover plaintext offsets.
   
   Using the plaintext offsets, I think we can reliably split AGS files that store Avro data:
   1. Convert AGS byte range splits into plaintext splits, removing any 0-byte splits (unlikely but possible)
   2. Implement an AGS stream that can seek to plaintext offsets (using the translation methods above)
   3. Pass the plaintext splits into the Avro reader with the plaintext seeking AGS stream
   
   @ggershinsky, what do you think?



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscribe@iceberg.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: issues-unsubscribe@iceberg.apache.org
For additional commands, e-mail: issues-help@iceberg.apache.org


[GitHub] [iceberg] ggershinsky commented on a diff in pull request #5432: AES GCM Stream Spec

Posted by GitBox <gi...@apache.org>.
ggershinsky commented on code in PR #5432:
URL: https://github.com/apache/iceberg/pull/5432#discussion_r938818925


##########
format/gcm-stream-spec.md:
##########
@@ -0,0 +1,89 @@
+---
+title: "AES GCM Stream Spec"
+url: gcm-stream-spec
+toc: true
+disableSidebar: true
+---
+<!--
+ - Licensed to the Apache Software Foundation (ASF) under one or more
+ - contributor license agreements.  See the NOTICE file distributed with
+ - this work for additional information regarding copyright ownership.
+ - The ASF licenses this file to You 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.
+ -->
+
+# AES GCM Stream (AGS) file format extension
+
+## Background and Motivation
+
+Iceberg supports a number of data file formats. Two of these formats (Parquet and ORC) have built-in encryption capabilities, that allow to protect sensitive information in the data files. However, besides the data files, Iceberg tables also have metadata files, that keep sensitive information too (e.g., min/max values in manifest files, or bloom filter bitsets in puffin files). Metadata file formats (AVRO, JSON, Puffin) don't have encryption support.
+
+Moreover, with the exception of Parquet, no Iceberg data or metadata file format supports integrity verification, required for end-to-end tamper proofing of Iceberg tables.
+
+This document specifies details of a simple file format extension that adds encryption and tamper-proofing to any existing file format.
+
+## Goals
+
+* Metadata encryption: enable encryption of manifests, manifest lists, snapshots and stats.
+* Avro data encryption: enable encryption of data files in tables that use the Avro format.
+* Tamper proofing of Iceberg data and metadata files.
+
+## Technical approach

Review Comment:
   Sounds good. We have a section with this name in a parquet spec, but I don't see it in the iceberg specs. I'll remove this section, and move the spec-related parts to the relevant sections.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscribe@iceberg.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: issues-unsubscribe@iceberg.apache.org
For additional commands, e-mail: issues-help@iceberg.apache.org


[GitHub] [iceberg] rdblue commented on a diff in pull request #5432: AES GCM Stream Spec

Posted by GitBox <gi...@apache.org>.
rdblue commented on code in PR #5432:
URL: https://github.com/apache/iceberg/pull/5432#discussion_r950916081


##########
format/gcm-stream-spec.md:
##########
@@ -0,0 +1,87 @@
+---
+title: "AES GCM Stream Spec"
+url: gcm-stream-spec
+toc: true
+disableSidebar: true
+---
+<!--
+ - Licensed to the Apache Software Foundation (ASF) under one or more
+ - contributor license agreements.  See the NOTICE file distributed with
+ - this work for additional information regarding copyright ownership.
+ - The ASF licenses this file to You 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.
+ -->
+
+# AES GCM Stream (AGS) file format extension
+
+## Background and Motivation
+
+Iceberg supports a number of data file formats. Two of these formats (Parquet and ORC) have built-in encryption capabilities, that allow to protect sensitive information in the data files. However, besides the data files, Iceberg tables also have metadata files, that keep sensitive information too (e.g., min/max values in manifest files, or bloom filter bitsets in puffin files). Metadata file formats (AVRO, JSON, Puffin) don't have encryption support.
+
+Moreover, with the exception of Parquet, no Iceberg data or metadata file format supports integrity verification, required for end-to-end tamper proofing of Iceberg tables.
+
+This document specifies details of a simple file format extension that adds encryption and tamper-proofing to any existing file format.
+
+## Goals
+
+* Metadata encryption: enable encryption of manifests, manifest lists, snapshots and stats.
+* Avro data encryption: enable encryption of data files in tables that use the Avro format.
+* Tamper proofing of Iceberg data and metadata files.
+
+## Overview
+
+The output stream, produced by a metadata or data writer, is split into equal-size blocks (plus residue). Each block is enciphered (encrypted/signed) with a given encryption key, and stored in a file in the AGS format. Upon reading, the stored cipherblocks are verified for integrity; then decrypted and passed to metadata or data readers.
+
+## Encryption algorithm
+
+AGS uses the standard AEG GCM cipher, and supports all AES key sizes: 128, 192 and 256 bits.
+
+AES GCM is an authenticated encryption. Besides data confidentiality (encryption), it supports two levels of integrity verification (authentication): of the data (default), and of the data combined with an optional AAD (“additional authenticated data”). An AAD is a free text to be authenticated, together with the data. The structure of AGS AADs is described below.
+
+AES GCM requires a unique vector to be provided for each encrypted block. In this document, the unique input to GCM encryption is called nonce (“number used once”). AGS encryption uses the RBG-based (random bit generator) nonce construction as defined in the section 8.2.2 of the NIST SP 800-38D document. For each encrypted block, AGS generates a unique nonce with a length of 12 bytes (96 bits).
+
+## Format specification
+
+### File structure
+
+The AGS-encrypted files have the following structure
+
+```
+Magic BlockLength CipherBlock₁ CipherBlock₂ ... CipherBlockₙ
+```
+
+where
+
+- `Magic` is four bytes 0x41, 0x47, 0x53, 0x31 ("AGS1", short for: AES GCM Stream, version 1)
+- `BlockLength` is four bytes (little endian) integer keeping the length of the equal-size split blocks before encryption. The length is specified in bytes.
+- `CipherBlockᵢ` is the i-th enciphered block in the file, with the structure defined below.
+
+### Cipher Block structure
+
+Cipher blocks have the following structure
+
+| nonce | ciphertext | tag |
+|-------|------------|-----|

Review Comment:
   To be able to split formats like Avro that are splittable, we need to be able to go back and forth between offsets in the underlying data stream and in the AGS stream. I think that's possible since this has a strict format. The header structure is 8 bytes (4 magic + 4 block length) and then there is 24 bytes of overhead per CipherBlock (12 nonce + 12 tag).
   
   For any given offset in the underlying stream, we can find the block where it will be found by dividing by the block length:
   
   ```python
   def plain_block_index(plain_offset, block_length):
       return offset // block_length
   ```
   
   Then we can skip to a given block:
   
   ```python
   def cipher_block_offset(block_index, block_length):
       return 8 + block_index * (24 + block_length)
   ```
   
   But the problem is that we don't get split offsets in the underlying file, we get split offsets in the AGS stream and need to figure out where in the underlying file those translate to, so that we don't have overlapping ranges that tasks are responsible for. We have a picture like this for a block size of 1024, 3 blocks, and a last block of size 553:
   
   |  | magic | block length | nonce-1 | ciphertext-1 | tag-1 | nonce-2 | ciphertext-2 | tag-2 | nonce-3 | ciphertext-3 | tag-3 | EOF |
   | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- |
   | AGS offset | 0 | 4 | 8 | 20 (to 1043) | 1044 | 1056 | 1068 (to 2091) | 2092 | 2104 | 2116 (to 2668) | 2669 | 2681 |
   | Stream offset |  |  |  | 0 (to 1023) |  |  | 1024 (to 2047) |  |  | 2048 (to 2601) |  | 2602 |
   
   To convert an AGS offset into a stream offset, I think we need to produce the the block index and an offset in that block. Producing the block index is the opposite of the `cipher_block_offset` function:
   
   ```python
   def cipher_block_index(cipher_offset, block_length):
       if (cipher_offset < 8):
           raise ValueError()
       return (cipher_offset - 8) // (block_length + 24)
   ```
   
   Then the offset in the plaintext block can be produced by subtracting the ciphertext offset from the start of the ciphertext block and some extra accounting:
   
   ```python
   def plaintext_block_offset(cipher_offset, block_length):
       block_index = cipher_block_index(cipher_offset, block_length)
       block_start = ciphertext_block_offset(block_index, block_length)
       local_offset = ciphertext_offset - block_start
       return local_offset if local_offset < block_length else block_length
   ```
   
   The check against `block_length` ensures that the local block offsets never overlap. Offsets that are between the ciphertext blocks (like 1048 in tag-1 for the example above) are mapped to the end of the plaintext block. This gives us a stable way to recover plaintext offsets.
   
   Using the plaintext offsets, I think we can reliably split AGS files that store Avro data:
   1. Convert AGS byte range splits into plaintext splits, removing any 0-byte splits (unlikely but possible)
   2. Implement an AGS stream that can seek to plaintext offsets (using the translation methods above)
   3. Pass the plaintext splits into the Avro reader with the plaintext seeking AGS stream
   
   @ggershinsky, what do you think?



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscribe@iceberg.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: issues-unsubscribe@iceberg.apache.org
For additional commands, e-mail: issues-help@iceberg.apache.org


[GitHub] [iceberg] rdblue commented on a diff in pull request #5432: AES GCM Stream Spec

Posted by GitBox <gi...@apache.org>.
rdblue commented on code in PR #5432:
URL: https://github.com/apache/iceberg/pull/5432#discussion_r950916081


##########
format/gcm-stream-spec.md:
##########
@@ -0,0 +1,87 @@
+---
+title: "AES GCM Stream Spec"
+url: gcm-stream-spec
+toc: true
+disableSidebar: true
+---
+<!--
+ - Licensed to the Apache Software Foundation (ASF) under one or more
+ - contributor license agreements.  See the NOTICE file distributed with
+ - this work for additional information regarding copyright ownership.
+ - The ASF licenses this file to You 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.
+ -->
+
+# AES GCM Stream (AGS) file format extension
+
+## Background and Motivation
+
+Iceberg supports a number of data file formats. Two of these formats (Parquet and ORC) have built-in encryption capabilities, that allow to protect sensitive information in the data files. However, besides the data files, Iceberg tables also have metadata files, that keep sensitive information too (e.g., min/max values in manifest files, or bloom filter bitsets in puffin files). Metadata file formats (AVRO, JSON, Puffin) don't have encryption support.
+
+Moreover, with the exception of Parquet, no Iceberg data or metadata file format supports integrity verification, required for end-to-end tamper proofing of Iceberg tables.
+
+This document specifies details of a simple file format extension that adds encryption and tamper-proofing to any existing file format.
+
+## Goals
+
+* Metadata encryption: enable encryption of manifests, manifest lists, snapshots and stats.
+* Avro data encryption: enable encryption of data files in tables that use the Avro format.
+* Tamper proofing of Iceberg data and metadata files.
+
+## Overview
+
+The output stream, produced by a metadata or data writer, is split into equal-size blocks (plus residue). Each block is enciphered (encrypted/signed) with a given encryption key, and stored in a file in the AGS format. Upon reading, the stored cipherblocks are verified for integrity; then decrypted and passed to metadata or data readers.
+
+## Encryption algorithm
+
+AGS uses the standard AEG GCM cipher, and supports all AES key sizes: 128, 192 and 256 bits.
+
+AES GCM is an authenticated encryption. Besides data confidentiality (encryption), it supports two levels of integrity verification (authentication): of the data (default), and of the data combined with an optional AAD (“additional authenticated data”). An AAD is a free text to be authenticated, together with the data. The structure of AGS AADs is described below.
+
+AES GCM requires a unique vector to be provided for each encrypted block. In this document, the unique input to GCM encryption is called nonce (“number used once”). AGS encryption uses the RBG-based (random bit generator) nonce construction as defined in the section 8.2.2 of the NIST SP 800-38D document. For each encrypted block, AGS generates a unique nonce with a length of 12 bytes (96 bits).
+
+## Format specification
+
+### File structure
+
+The AGS-encrypted files have the following structure
+
+```
+Magic BlockLength CipherBlock₁ CipherBlock₂ ... CipherBlockₙ
+```
+
+where
+
+- `Magic` is four bytes 0x41, 0x47, 0x53, 0x31 ("AGS1", short for: AES GCM Stream, version 1)
+- `BlockLength` is four bytes (little endian) integer keeping the length of the equal-size split blocks before encryption. The length is specified in bytes.
+- `CipherBlockᵢ` is the i-th enciphered block in the file, with the structure defined below.
+
+### Cipher Block structure
+
+Cipher blocks have the following structure
+
+| nonce | ciphertext | tag |
+|-------|------------|-----|

Review Comment:
   To be able to split formats like Avro that are splittable, we need to be able to go back and forth between offsets in the underlying data stream and in the AGS stream. I think that's possible since this has a strict format. The header structure is 8 bytes (4 magic + 4 block length) and then there is 24 bytes of overhead per CipherBlock (12 nonce + 12 tag).
   
   For any given offset in the underlying stream, we can find the block where it will be found by dividing by the block length:
   
   ```python
   def plain_block_index(plain_offset, block_length):
       return offset // block_length
   ```
   
   Then we can skip to a given block:
   
   ```python
   def cipher_block_offset(block_index, block_length):
       return 8 + block_index * (24 + block_length)
   ```
   
   But the problem is that we don't get split offsets in the underlying file, we get split offsets in the AGS stream and need to figure out where in the underlying file those translate to, so that we don't have overlapping ranges that tasks are responsible for. We have a picture like this for a block size of 1024, 3 blocks, and a last block of size 553:
   
   |  | magic | block length | nonce-1 | ciphertext-1 | tag-1 | nonce-2 | ciphertext-2 | tag-2 | nonce-3 | ciphertext-3 | tag-3 | EOF |
   | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- |
   | AGS offset | 0 | 4 | 8 | 20 (to 1043) | 1044 | 1056 | 1068 (to 2091) | 2092 | 2104 | 2116 (to 2668) | 2669 | 2681 |
   | Stream offset |  |  |  | 0 (to 1023) |  |  | 1024 (to 2047) |  |  | 2048 (to 2601) |  | 2602 |
   
   To convert an AGS offset into a stream offset, I think we need to produce the the block index and an offset in that block. Producing the block index is the opposite of the `cipher_block_offset` function:
   
   ```python
   def cipher_block_index(cipher_offset, block_length):
       if (cipher_offset < 8):
           raise ValueError()
       return (cipher_offset - 8) // (block_length + 24)
   ```
   
   Then the offset in the plaintext block can be produced by subtracting the ciphertext offset from the start of the ciphertext block and some extra accounting:
   
   ```python
   def plaintext_block_offset(cipher_offset, block_length):
       block_index = cipher_block_index(cipher_offset, block_length)
       block_start = cipher_block_offset(block_index, block_length)
       local_offset = ciphert_offset - block_start
       return min(local_offset, block_length)
   ```
   
   The check against `block_length` ensures that the local block offsets never overlap. Offsets that are between the ciphertext blocks (like 1048 in tag-1 for the example above) are mapped to the end of the plaintext block. This gives us a stable way to recover plaintext offsets.
   
   Using the plaintext offsets, I think we can reliably split AGS files that store Avro data:
   1. Convert AGS byte range splits into plaintext splits, removing any 0-byte splits (unlikely but possible)
   2. Implement an AGS stream that can seek to plaintext offsets (using the translation methods above)
   3. Pass the plaintext splits into the Avro reader with the plaintext seeking AGS stream
   
   @ggershinsky, what do you think?



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscribe@iceberg.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: issues-unsubscribe@iceberg.apache.org
For additional commands, e-mail: issues-help@iceberg.apache.org


[GitHub] [iceberg] ggershinsky commented on a diff in pull request #5432: AES GCM Stream Spec

Posted by GitBox <gi...@apache.org>.
ggershinsky commented on code in PR #5432:
URL: https://github.com/apache/iceberg/pull/5432#discussion_r963378482


##########
format/gcm-stream-spec.md:
##########
@@ -0,0 +1,87 @@
+---
+title: "AES GCM Stream Spec"
+url: gcm-stream-spec
+toc: true
+disableSidebar: true
+---
+<!--
+ - Licensed to the Apache Software Foundation (ASF) under one or more
+ - contributor license agreements.  See the NOTICE file distributed with
+ - this work for additional information regarding copyright ownership.
+ - The ASF licenses this file to You 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.
+ -->
+
+# AES GCM Stream (AGS) file format extension
+
+## Background and Motivation
+
+Iceberg supports a number of data file formats. Two of these formats (Parquet and ORC) have built-in encryption capabilities, that allow to protect sensitive information in the data files. However, besides the data files, Iceberg tables also have metadata files, that keep sensitive information too (e.g., min/max values in manifest files, or bloom filter bitsets in puffin files). Metadata file formats (AVRO, JSON, Puffin) don't have encryption support.
+
+Moreover, with the exception of Parquet, no Iceberg data or metadata file format supports integrity verification, required for end-to-end tamper proofing of Iceberg tables.
+
+This document specifies details of a simple file format extension that adds encryption and tamper-proofing to any existing file format.
+
+## Goals
+
+* Metadata encryption: enable encryption of manifests, manifest lists, snapshots and stats.
+* Avro data encryption: enable encryption of data files in tables that use the Avro format.
+* Tamper proofing of Iceberg data and metadata files.
+
+## Overview
+
+The output stream, produced by a metadata or data writer, is split into equal-size blocks (plus residue). Each block is enciphered (encrypted/signed) with a given encryption key, and stored in a file in the AGS format. Upon reading, the stored cipherblocks are verified for integrity; then decrypted and passed to metadata or data readers.
+
+## Encryption algorithm
+
+AGS uses the standard AEG GCM cipher, and supports all AES key sizes: 128, 192 and 256 bits.
+
+AES GCM is an authenticated encryption. Besides data confidentiality (encryption), it supports two levels of integrity verification (authentication): of the data (default), and of the data combined with an optional AAD (“additional authenticated data”). An AAD is a free text to be authenticated, together with the data. The structure of AGS AADs is described below.
+
+AES GCM requires a unique vector to be provided for each encrypted block. In this document, the unique input to GCM encryption is called nonce (“number used once”). AGS encryption uses the RBG-based (random bit generator) nonce construction as defined in the section 8.2.2 of the NIST SP 800-38D document. For each encrypted block, AGS generates a unique nonce with a length of 12 bytes (96 bits).
+
+## Format specification
+
+### File structure
+
+The AGS-encrypted files have the following structure
+
+```
+Magic BlockLength CipherBlock₁ CipherBlock₂ ... CipherBlockₙ
+```
+
+where
+
+- `Magic` is four bytes 0x41, 0x47, 0x53, 0x31 ("AGS1", short for: AES GCM Stream, version 1)
+- `BlockLength` is four bytes (little endian) integer keeping the length of the equal-size split blocks before encryption. The length is specified in bytes.
+- `CipherBlockᵢ` is the i-th enciphered block in the file, with the structure defined below.
+
+### Cipher Block structure
+
+Cipher blocks have the following structure
+
+| nonce | ciphertext | tag |
+|-------|------------|-----|

Review Comment:
   @rdblue I'm back in office, went through this carefully. I believe we are on the same page. The technical approach you describe is the same as used in the spec implementation [PR](https://github.com/apache/iceberg/pull/3231/files) 
   
   At a high level, this should be fully transparent to the current Avro readers. The API they use (file `getLength`; stream `skip`, `seek`, `getPos`) return the same values and work the same as before/without AGS encryption. This is the AGS code job to translate the plaintext<->ciphertext stuff behind the scenes. So, as long as the Avro split functionality depends on these APIs, it should continue to work as usual with the AGS encrypted files.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscribe@iceberg.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: issues-unsubscribe@iceberg.apache.org
For additional commands, e-mail: issues-help@iceberg.apache.org


[GitHub] [iceberg] rdblue commented on a diff in pull request #5432: AES GCM Stream Spec

Posted by GitBox <gi...@apache.org>.
rdblue commented on code in PR #5432:
URL: https://github.com/apache/iceberg/pull/5432#discussion_r1015856883


##########
format/gcm-stream-spec.md:
##########
@@ -0,0 +1,87 @@
+---
+title: "AES GCM Stream Spec"
+url: gcm-stream-spec
+toc: true
+disableSidebar: true
+---
+<!--
+ - Licensed to the Apache Software Foundation (ASF) under one or more
+ - contributor license agreements.  See the NOTICE file distributed with
+ - this work for additional information regarding copyright ownership.
+ - The ASF licenses this file to You 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.
+ -->
+
+# AES GCM Stream (AGS) file format extension
+
+## Background and Motivation
+
+Iceberg supports a number of data file formats. Two of these formats (Parquet and ORC) have built-in encryption capabilities, that allow to protect sensitive information in the data files. However, besides the data files, Iceberg tables also have metadata files, that keep sensitive information too (e.g., min/max values in manifest files, or bloom filter bitsets in puffin files). Metadata file formats (AVRO, JSON, Puffin) don't have encryption support.
+
+Moreover, with the exception of Parquet, no Iceberg data or metadata file format supports integrity verification, required for end-to-end tamper proofing of Iceberg tables.
+
+This document specifies details of a simple file format extension that adds encryption and tamper-proofing to any existing file format.
+
+## Goals
+
+* Metadata encryption: enable encryption of manifests, manifest lists, snapshots and stats.
+* Avro data encryption: enable encryption of data files in tables that use the Avro format.

Review Comment:
   Can you add this?



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscribe@iceberg.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: issues-unsubscribe@iceberg.apache.org
For additional commands, e-mail: issues-help@iceberg.apache.org


[GitHub] [iceberg] ggershinsky commented on a diff in pull request #5432: AES GCM Stream Spec

Posted by GitBox <gi...@apache.org>.
ggershinsky commented on code in PR #5432:
URL: https://github.com/apache/iceberg/pull/5432#discussion_r963342215


##########
format/gcm-stream-spec.md:
##########
@@ -0,0 +1,87 @@
+---
+title: "AES GCM Stream Spec"
+url: gcm-stream-spec
+toc: true
+disableSidebar: true
+---
+<!--
+ - Licensed to the Apache Software Foundation (ASF) under one or more
+ - contributor license agreements.  See the NOTICE file distributed with
+ - this work for additional information regarding copyright ownership.
+ - The ASF licenses this file to You 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.
+ -->
+
+# AES GCM Stream (AGS) file format extension
+
+## Background and Motivation
+
+Iceberg supports a number of data file formats. Two of these formats (Parquet and ORC) have built-in encryption capabilities, that allow to protect sensitive information in the data files. However, besides the data files, Iceberg tables also have metadata files, that keep sensitive information too (e.g., min/max values in manifest files, or bloom filter bitsets in puffin files). Metadata file formats (AVRO, JSON, Puffin) don't have encryption support.
+
+Moreover, with the exception of Parquet, no Iceberg data or metadata file format supports integrity verification, required for end-to-end tamper proofing of Iceberg tables.
+
+This document specifies details of a simple file format extension that adds encryption and tamper-proofing to any existing file format.
+
+## Goals
+
+* Metadata encryption: enable encryption of manifests, manifest lists, snapshots and stats.
+* Avro data encryption: enable encryption of data files in tables that use the Avro format.
+* Tamper proofing of Iceberg data and metadata files.
+
+## Overview
+
+The output stream, produced by a metadata or data writer, is split into equal-size blocks (plus residue). Each block is enciphered (encrypted/signed) with a given encryption key, and stored in a file in the AGS format. Upon reading, the stored cipherblocks are verified for integrity; then decrypted and passed to metadata or data readers.

Review Comment:
   will do (briefly in this overview section; in detail in the spec section)



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscribe@iceberg.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: issues-unsubscribe@iceberg.apache.org
For additional commands, e-mail: issues-help@iceberg.apache.org


[GitHub] [iceberg] ggershinsky commented on a diff in pull request #5432: AES GCM Stream Spec

Posted by GitBox <gi...@apache.org>.
ggershinsky commented on code in PR #5432:
URL: https://github.com/apache/iceberg/pull/5432#discussion_r963348014


##########
format/gcm-stream-spec.md:
##########
@@ -0,0 +1,87 @@
+---
+title: "AES GCM Stream Spec"
+url: gcm-stream-spec
+toc: true
+disableSidebar: true
+---
+<!--
+ - Licensed to the Apache Software Foundation (ASF) under one or more
+ - contributor license agreements.  See the NOTICE file distributed with
+ - this work for additional information regarding copyright ownership.
+ - The ASF licenses this file to You 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.
+ -->
+
+# AES GCM Stream (AGS) file format extension

Review Comment:
   While AES GCM is a NIST standard, AES GCM Stream is a new concept introduced in Iceberg. This is a file encryption stream, based on the GCM properties, so the "AES GCM Stream" (and AGS for short references where needed) seem to be a reasonable naming; but there might be other options.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscribe@iceberg.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: issues-unsubscribe@iceberg.apache.org
For additional commands, e-mail: issues-help@iceberg.apache.org


[GitHub] [iceberg] rdblue commented on a diff in pull request #5432: AES GCM Stream Spec

Posted by GitBox <gi...@apache.org>.
rdblue commented on code in PR #5432:
URL: https://github.com/apache/iceberg/pull/5432#discussion_r950916081


##########
format/gcm-stream-spec.md:
##########
@@ -0,0 +1,87 @@
+---
+title: "AES GCM Stream Spec"
+url: gcm-stream-spec
+toc: true
+disableSidebar: true
+---
+<!--
+ - Licensed to the Apache Software Foundation (ASF) under one or more
+ - contributor license agreements.  See the NOTICE file distributed with
+ - this work for additional information regarding copyright ownership.
+ - The ASF licenses this file to You 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.
+ -->
+
+# AES GCM Stream (AGS) file format extension
+
+## Background and Motivation
+
+Iceberg supports a number of data file formats. Two of these formats (Parquet and ORC) have built-in encryption capabilities, that allow to protect sensitive information in the data files. However, besides the data files, Iceberg tables also have metadata files, that keep sensitive information too (e.g., min/max values in manifest files, or bloom filter bitsets in puffin files). Metadata file formats (AVRO, JSON, Puffin) don't have encryption support.
+
+Moreover, with the exception of Parquet, no Iceberg data or metadata file format supports integrity verification, required for end-to-end tamper proofing of Iceberg tables.
+
+This document specifies details of a simple file format extension that adds encryption and tamper-proofing to any existing file format.
+
+## Goals
+
+* Metadata encryption: enable encryption of manifests, manifest lists, snapshots and stats.
+* Avro data encryption: enable encryption of data files in tables that use the Avro format.
+* Tamper proofing of Iceberg data and metadata files.
+
+## Overview
+
+The output stream, produced by a metadata or data writer, is split into equal-size blocks (plus residue). Each block is enciphered (encrypted/signed) with a given encryption key, and stored in a file in the AGS format. Upon reading, the stored cipherblocks are verified for integrity; then decrypted and passed to metadata or data readers.
+
+## Encryption algorithm
+
+AGS uses the standard AEG GCM cipher, and supports all AES key sizes: 128, 192 and 256 bits.
+
+AES GCM is an authenticated encryption. Besides data confidentiality (encryption), it supports two levels of integrity verification (authentication): of the data (default), and of the data combined with an optional AAD (“additional authenticated data”). An AAD is a free text to be authenticated, together with the data. The structure of AGS AADs is described below.
+
+AES GCM requires a unique vector to be provided for each encrypted block. In this document, the unique input to GCM encryption is called nonce (“number used once”). AGS encryption uses the RBG-based (random bit generator) nonce construction as defined in the section 8.2.2 of the NIST SP 800-38D document. For each encrypted block, AGS generates a unique nonce with a length of 12 bytes (96 bits).
+
+## Format specification
+
+### File structure
+
+The AGS-encrypted files have the following structure
+
+```
+Magic BlockLength CipherBlock₁ CipherBlock₂ ... CipherBlockₙ
+```
+
+where
+
+- `Magic` is four bytes 0x41, 0x47, 0x53, 0x31 ("AGS1", short for: AES GCM Stream, version 1)
+- `BlockLength` is four bytes (little endian) integer keeping the length of the equal-size split blocks before encryption. The length is specified in bytes.
+- `CipherBlockᵢ` is the i-th enciphered block in the file, with the structure defined below.
+
+### Cipher Block structure
+
+Cipher blocks have the following structure
+
+| nonce | ciphertext | tag |
+|-------|------------|-----|

Review Comment:
   To be able to split formats like Avro that are splittable, we need to be able to go back and forth between offsets in the underlying data stream and in the AGS stream. I think that's possible since this has a strict format. The header structure is 8 bytes (4 magic + 4 block length) and then there is 24 bytes of overhead per CipherBlock (12 nonce + 12 tag).
   
   For any given offset in the underlying stream, we can find the block where it will be found by dividing by the block length:
   
   ```python
   def plain_block_index(plain_offset, block_length):
       return offset // block_length
   ```
   
   Then we can skip to a given block:
   
   ```python
   def cipher_block_offset(block_index, block_length):
       return 8 + block_index * (24 + block_length)
   ```
   
   But the problem is that we don't get split offsets in the underlying file, we get split offsets in the AGS stream and need to figure out where in the underlying file those translate to, so that we don't have overlapping ranges that tasks are responsible for. We have a picture like this for a block size of 1024, 3 blocks, and a last block of size 553:
   
   |  | magic | block length | nonce-1 | ciphertext-1 | tag-1 | nonce-2 | ciphertext-2 | tag-2 | nonce-3 | ciphertext-3 | tag-3 | EOF |
   | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- |
   | AGS offset | 0 | 4 | 8 | 20 (to 1043) | 1044 | 1056 | 1068 (to 2091) | 2092 | 2104 | 2116 (to 2668) | 2669 | 2681 |
   | Stream offset |  |  |  | 0 (to 1023) |  |  | 1024 (to 2047) |  |  | 2048 (to 2601) |  | 2602 |
   
   To convert an AGS offset into a stream offset, I think we need to produce the the block index and an offset in that block. Producing the block index is the opposite of the `cipher_block_offset` function:
   
   ```python
   def cipher_block_index(cipher_offset, block_length):
       if (cipher_offset < 8):
           raise ValueError()
       return (cipher_offset - 8) // (block_length + 24)
   ```
   
   Then the offset in the plaintext block can be produced by subtracting the ciphertext offset from the start of the ciphertext block and some extra accounting:
   
   ```python
   def plaintext_block_offset(cipher_offset, block_length):
       block_index = cipher_block_index(cipher_offset, block_length)
       block_start = cipher_block_offset(block_index, block_length)
       local_offset = ciphert_offset - block_start
       return min(local_offset, block_length)
   ```
   
   The min with `block_length` ensures that the local block offsets never overlap. Offsets that are between the ciphertext blocks (like 1048 in tag-1 for the example above) are mapped to the end of the plaintext block. This gives us a stable way to recover plaintext offsets.
   
   Using the plaintext offsets, I think we can reliably split AGS files that store Avro data:
   1. Convert AGS byte range splits into plaintext splits, removing any 0-byte splits (unlikely but possible)
   2. Implement an AGS stream that can seek to plaintext offsets (using the translation methods above)
   3. Pass the plaintext splits into the Avro reader with the plaintext seeking AGS stream
   
   @ggershinsky, what do you think?



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscribe@iceberg.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: issues-unsubscribe@iceberg.apache.org
For additional commands, e-mail: issues-help@iceberg.apache.org


[GitHub] [iceberg] rdblue commented on a diff in pull request #5432: AES GCM Stream Spec

Posted by GitBox <gi...@apache.org>.
rdblue commented on code in PR #5432:
URL: https://github.com/apache/iceberg/pull/5432#discussion_r950916081


##########
format/gcm-stream-spec.md:
##########
@@ -0,0 +1,87 @@
+---
+title: "AES GCM Stream Spec"
+url: gcm-stream-spec
+toc: true
+disableSidebar: true
+---
+<!--
+ - Licensed to the Apache Software Foundation (ASF) under one or more
+ - contributor license agreements.  See the NOTICE file distributed with
+ - this work for additional information regarding copyright ownership.
+ - The ASF licenses this file to You 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.
+ -->
+
+# AES GCM Stream (AGS) file format extension
+
+## Background and Motivation
+
+Iceberg supports a number of data file formats. Two of these formats (Parquet and ORC) have built-in encryption capabilities, that allow to protect sensitive information in the data files. However, besides the data files, Iceberg tables also have metadata files, that keep sensitive information too (e.g., min/max values in manifest files, or bloom filter bitsets in puffin files). Metadata file formats (AVRO, JSON, Puffin) don't have encryption support.
+
+Moreover, with the exception of Parquet, no Iceberg data or metadata file format supports integrity verification, required for end-to-end tamper proofing of Iceberg tables.
+
+This document specifies details of a simple file format extension that adds encryption and tamper-proofing to any existing file format.
+
+## Goals
+
+* Metadata encryption: enable encryption of manifests, manifest lists, snapshots and stats.
+* Avro data encryption: enable encryption of data files in tables that use the Avro format.
+* Tamper proofing of Iceberg data and metadata files.
+
+## Overview
+
+The output stream, produced by a metadata or data writer, is split into equal-size blocks (plus residue). Each block is enciphered (encrypted/signed) with a given encryption key, and stored in a file in the AGS format. Upon reading, the stored cipherblocks are verified for integrity; then decrypted and passed to metadata or data readers.
+
+## Encryption algorithm
+
+AGS uses the standard AEG GCM cipher, and supports all AES key sizes: 128, 192 and 256 bits.
+
+AES GCM is an authenticated encryption. Besides data confidentiality (encryption), it supports two levels of integrity verification (authentication): of the data (default), and of the data combined with an optional AAD (“additional authenticated data”). An AAD is a free text to be authenticated, together with the data. The structure of AGS AADs is described below.
+
+AES GCM requires a unique vector to be provided for each encrypted block. In this document, the unique input to GCM encryption is called nonce (“number used once”). AGS encryption uses the RBG-based (random bit generator) nonce construction as defined in the section 8.2.2 of the NIST SP 800-38D document. For each encrypted block, AGS generates a unique nonce with a length of 12 bytes (96 bits).
+
+## Format specification
+
+### File structure
+
+The AGS-encrypted files have the following structure
+
+```
+Magic BlockLength CipherBlock₁ CipherBlock₂ ... CipherBlockₙ
+```
+
+where
+
+- `Magic` is four bytes 0x41, 0x47, 0x53, 0x31 ("AGS1", short for: AES GCM Stream, version 1)
+- `BlockLength` is four bytes (little endian) integer keeping the length of the equal-size split blocks before encryption. The length is specified in bytes.
+- `CipherBlockᵢ` is the i-th enciphered block in the file, with the structure defined below.
+
+### Cipher Block structure
+
+Cipher blocks have the following structure
+
+| nonce | ciphertext | tag |
+|-------|------------|-----|

Review Comment:
   To be able to split formats like Avro that are splittable, we need to be able to go back and forth between offsets in the underlying data stream and in the AGS stream. I think that's possible since this has a strict format. The header structure is 8 bytes (4 magic + 4 block length) and then there is 24 bytes of overhead per CipherBlock (12 nonce + 12 tag).
   
   For any given offset in the underlying stream, we can find the block where it will be found by dividing by the block length:
   
   ```python
   def plain_block_index(plain_offset, block_length):
       return offset // block_length
   ```
   
   Then we can skip to a given block:
   
   ```python
   def cipher_block_offset(block_index, block_length):
       return 8 + block_index * (24 + block_length)
   ```
   
   But the problem is that we don't get split offsets in the underlying file, we get split offsets in the AGS stream and need to figure out where in the underlying file those translate to, so that we don't have overlapping ranges that tasks are responsible for. We have a picture like this for a block size of 1024, 3 blocks, and a last block of size 553:
   
   |  | magic | block length | nonce-1 | ciphertext-1 | tag-1 | nonce-2 | ciphertext-2 | tag-2 | nonce-3 | ciphertext-3 | tag-3 | EOF |
   | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- |
   | AGS offset | 0 | 4 | 8 | 20 (to 1043) | 1044 | 1056 | 1068 (to 2091) | 2092 | 2104 | 2116 (to 2668) | 2669 | 2681 |
   | Stream offset |  |  |  | 0 (to 1023) |  |  | 1024 (to 2047) |  |  | 2048 (to 2601) |  | 2602 |
   
   To convert an AGS offset into a stream offset, I think we need to produce the the block index and an offset in that block. Producing the block index is the opposite of the `cipher_block_offset` function:
   
   ```python
   def cipher_block_index(cipher_offset, block_length):
       if (cipher_offset < 8):
           raise ValueError()
       return (cipher_offset - 8) // (block_length + 24)
   ```
   
   Then the offset in the plaintext block can be produced by subtracting the ciphertext offset from the start of the ciphertext block and some extra accounting:
   
   ```python
   def plaintext_offset(cipher_offset, block_length):
       block_index = cipher_block_index(cipher_offset, block_length)
       block_start = cipher_block_offset(block_index, block_length)
       local_offset = min(cipher_offset - block_start, block_length)
       return block_index * block_length + local_offset
   ```
   
   The min with `block_length` ensures that the local block offsets never overlap. Offsets that are between the ciphertext blocks (like 1048 in tag-1 for the example above) are mapped to the end of the plaintext block. This gives us a stable way to recover plaintext offsets.
   
   Using the plaintext offsets, I think we can reliably split AGS files that store Avro data:
   1. Convert AGS byte range splits into plaintext splits, removing any 0-byte splits (unlikely but possible)
   2. Implement an AGS stream that can seek to plaintext offsets (using the translation methods above)
   3. Pass the plaintext splits into the Avro reader with the plaintext seeking AGS stream
   
   @ggershinsky, what do you think?



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscribe@iceberg.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: issues-unsubscribe@iceberg.apache.org
For additional commands, e-mail: issues-help@iceberg.apache.org


[GitHub] [iceberg] ggershinsky commented on a diff in pull request #5432: AES GCM Stream Spec

Posted by GitBox <gi...@apache.org>.
ggershinsky commented on code in PR #5432:
URL: https://github.com/apache/iceberg/pull/5432#discussion_r969908500


##########
format/gcm-stream-spec.md:
##########
@@ -0,0 +1,87 @@
+---
+title: "AES GCM Stream Spec"
+url: gcm-stream-spec
+toc: true
+disableSidebar: true
+---
+<!--
+ - Licensed to the Apache Software Foundation (ASF) under one or more
+ - contributor license agreements.  See the NOTICE file distributed with
+ - this work for additional information regarding copyright ownership.
+ - The ASF licenses this file to You 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.
+ -->
+
+# AES GCM Stream (AGS) file format extension
+
+## Background and Motivation
+
+Iceberg supports a number of data file formats. Two of these formats (Parquet and ORC) have built-in encryption capabilities, that allow to protect sensitive information in the data files. However, besides the data files, Iceberg tables also have metadata files, that keep sensitive information too (e.g., min/max values in manifest files, or bloom filter bitsets in puffin files). Metadata file formats (AVRO, JSON, Puffin) don't have encryption support.
+
+Moreover, with the exception of Parquet, no Iceberg data or metadata file format supports integrity verification, required for end-to-end tamper proofing of Iceberg tables.
+
+This document specifies details of a simple file format extension that adds encryption and tamper-proofing to any existing file format.
+
+## Goals
+
+* Metadata encryption: enable encryption of manifests, manifest lists, snapshots and stats.
+* Avro data encryption: enable encryption of data files in tables that use the Avro format.
+* Tamper proofing of Iceberg data and metadata files.
+
+## Overview
+
+The output stream, produced by a metadata or data writer, is split into equal-size blocks (plus residue). Each block is enciphered (encrypted/signed) with a given encryption key, and stored in a file in the AGS format. Upon reading, the stored cipherblocks are verified for integrity; then decrypted and passed to metadata or data readers.
+
+## Encryption algorithm
+
+AGS uses the standard AEG GCM cipher, and supports all AES key sizes: 128, 192 and 256 bits.
+
+AES GCM is an authenticated encryption. Besides data confidentiality (encryption), it supports two levels of integrity verification (authentication): of the data (default), and of the data combined with an optional AAD (“additional authenticated data”). An AAD is a free text to be authenticated, together with the data. The structure of AGS AADs is described below.
+
+AES GCM requires a unique vector to be provided for each encrypted block. In this document, the unique input to GCM encryption is called nonce (“number used once”). AGS encryption uses the RBG-based (random bit generator) nonce construction as defined in the section 8.2.2 of the NIST SP 800-38D document. For each encrypted block, AGS generates a unique nonce with a length of 12 bytes (96 bits).
+
+## Format specification
+
+### File structure
+
+The AGS-encrypted files have the following structure
+
+```
+Magic BlockLength CipherBlock₁ CipherBlock₂ ... CipherBlockₙ
+```
+
+where
+
+- `Magic` is four bytes 0x41, 0x47, 0x53, 0x31 ("AGS1", short for: AES GCM Stream, version 1)
+- `BlockLength` is four bytes (little endian) integer keeping the length of the equal-size split blocks before encryption. The length is specified in bytes.
+- `CipherBlockᵢ` is the i-th enciphered block in the file, with the structure defined below.
+
+### Cipher Block structure
+
+Cipher blocks have the following structure
+
+| nonce | ciphertext | tag |
+|-------|------------|-----|

Review Comment:
   @rdblue what do you think?



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscribe@iceberg.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: issues-unsubscribe@iceberg.apache.org
For additional commands, e-mail: issues-help@iceberg.apache.org


[GitHub] [iceberg] rdblue commented on a diff in pull request #5432: AES GCM Stream Spec

Posted by GitBox <gi...@apache.org>.
rdblue commented on code in PR #5432:
URL: https://github.com/apache/iceberg/pull/5432#discussion_r1015857790


##########
format/gcm-stream-spec.md:
##########
@@ -0,0 +1,87 @@
+---
+title: "AES GCM Stream Spec"
+url: gcm-stream-spec
+toc: true
+disableSidebar: true
+---
+<!--
+ - Licensed to the Apache Software Foundation (ASF) under one or more
+ - contributor license agreements.  See the NOTICE file distributed with
+ - this work for additional information regarding copyright ownership.
+ - The ASF licenses this file to You 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.
+ -->
+
+# AES GCM Stream (AGS) file format extension
+
+## Background and Motivation
+
+Iceberg supports a number of data file formats. Two of these formats (Parquet and ORC) have built-in encryption capabilities, that allow to protect sensitive information in the data files. However, besides the data files, Iceberg tables also have metadata files, that keep sensitive information too (e.g., min/max values in manifest files, or bloom filter bitsets in puffin files). Metadata file formats (AVRO, JSON, Puffin) don't have encryption support.
+
+Moreover, with the exception of Parquet, no Iceberg data or metadata file format supports integrity verification, required for end-to-end tamper proofing of Iceberg tables.
+
+This document specifies details of a simple file format extension that adds encryption and tamper-proofing to any existing file format.
+
+## Goals
+
+* Metadata encryption: enable encryption of manifests, manifest lists, snapshots and stats.
+* Avro data encryption: enable encryption of data files in tables that use the Avro format.
+* Tamper proofing of Iceberg data and metadata files.
+
+## Overview
+
+The output stream, produced by a metadata or data writer, is split into equal-size blocks (plus residue). Each block is enciphered (encrypted/signed) with a given encryption key, and stored in a file in the AGS format. Upon reading, the stored cipherblocks are verified for integrity; then decrypted and passed to metadata or data readers.
+
+## Encryption algorithm
+
+AGS uses the standard AEG GCM cipher, and supports all AES key sizes: 128, 192 and 256 bits.
+
+AES GCM is an authenticated encryption. Besides data confidentiality (encryption), it supports two levels of integrity verification (authentication): of the data (default), and of the data combined with an optional AAD (“additional authenticated data”). An AAD is a free text to be authenticated, together with the data. The structure of AGS AADs is described below.
+
+AES GCM requires a unique vector to be provided for each encrypted block. In this document, the unique input to GCM encryption is called nonce (“number used once”). AGS encryption uses the RBG-based (random bit generator) nonce construction as defined in the section 8.2.2 of the NIST SP 800-38D document. For each encrypted block, AGS generates a unique nonce with a length of 12 bytes (96 bits).
+
+## Format specification
+
+### File structure
+
+The AGS-encrypted files have the following structure
+
+```
+Magic BlockLength CipherBlock₁ CipherBlock₂ ... CipherBlockₙ
+```
+
+where
+
+- `Magic` is four bytes 0x41, 0x47, 0x53, 0x31 ("AGS1", short for: AES GCM Stream, version 1)
+- `BlockLength` is four bytes (little endian) integer keeping the length of the equal-size split blocks before encryption. The length is specified in bytes.
+- `CipherBlockᵢ` is the i-th enciphered block in the file, with the structure defined below.
+
+### Cipher Block structure
+
+Cipher blocks have the following structure
+
+| nonce | ciphertext | tag |
+|-------|------------|-----|

Review Comment:
   I think that this should work.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscribe@iceberg.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: issues-unsubscribe@iceberg.apache.org
For additional commands, e-mail: issues-help@iceberg.apache.org


[GitHub] [iceberg] ggershinsky commented on a diff in pull request #5432: AES GCM Stream Spec

Posted by GitBox <gi...@apache.org>.
ggershinsky commented on code in PR #5432:
URL: https://github.com/apache/iceberg/pull/5432#discussion_r951078855


##########
format/gcm-stream-spec.md:
##########
@@ -0,0 +1,87 @@
+---
+title: "AES GCM Stream Spec"
+url: gcm-stream-spec
+toc: true
+disableSidebar: true
+---
+<!--
+ - Licensed to the Apache Software Foundation (ASF) under one or more
+ - contributor license agreements.  See the NOTICE file distributed with
+ - this work for additional information regarding copyright ownership.
+ - The ASF licenses this file to You 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.
+ -->
+
+# AES GCM Stream (AGS) file format extension
+
+## Background and Motivation
+
+Iceberg supports a number of data file formats. Two of these formats (Parquet and ORC) have built-in encryption capabilities, that allow to protect sensitive information in the data files. However, besides the data files, Iceberg tables also have metadata files, that keep sensitive information too (e.g., min/max values in manifest files, or bloom filter bitsets in puffin files). Metadata file formats (AVRO, JSON, Puffin) don't have encryption support.
+
+Moreover, with the exception of Parquet, no Iceberg data or metadata file format supports integrity verification, required for end-to-end tamper proofing of Iceberg tables.
+
+This document specifies details of a simple file format extension that adds encryption and tamper-proofing to any existing file format.
+
+## Goals
+
+* Metadata encryption: enable encryption of manifests, manifest lists, snapshots and stats.
+* Avro data encryption: enable encryption of data files in tables that use the Avro format.
+* Tamper proofing of Iceberg data and metadata files.
+
+## Overview
+
+The output stream, produced by a metadata or data writer, is split into equal-size blocks (plus residue). Each block is enciphered (encrypted/signed) with a given encryption key, and stored in a file in the AGS format. Upon reading, the stored cipherblocks are verified for integrity; then decrypted and passed to metadata or data readers.
+
+## Encryption algorithm
+
+AGS uses the standard AEG GCM cipher, and supports all AES key sizes: 128, 192 and 256 bits.
+
+AES GCM is an authenticated encryption. Besides data confidentiality (encryption), it supports two levels of integrity verification (authentication): of the data (default), and of the data combined with an optional AAD (“additional authenticated data”). An AAD is a free text to be authenticated, together with the data. The structure of AGS AADs is described below.
+
+AES GCM requires a unique vector to be provided for each encrypted block. In this document, the unique input to GCM encryption is called nonce (“number used once”). AGS encryption uses the RBG-based (random bit generator) nonce construction as defined in the section 8.2.2 of the NIST SP 800-38D document. For each encrypted block, AGS generates a unique nonce with a length of 12 bytes (96 bits).
+
+## Format specification
+
+### File structure
+
+The AGS-encrypted files have the following structure
+
+```
+Magic BlockLength CipherBlock₁ CipherBlock₂ ... CipherBlockₙ
+```
+
+where
+
+- `Magic` is four bytes 0x41, 0x47, 0x53, 0x31 ("AGS1", short for: AES GCM Stream, version 1)
+- `BlockLength` is four bytes (little endian) integer keeping the length of the equal-size split blocks before encryption. The length is specified in bytes.
+- `CipherBlockᵢ` is the i-th enciphered block in the file, with the structure defined below.
+
+### Cipher Block structure
+
+Cipher blocks have the following structure
+
+| nonce | ciphertext | tag |
+|-------|------------|-----|

Review Comment:
   @rdblue , thanks! I need to think deeper about this; currently on vacation; will respond the first week of September.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscribe@iceberg.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: issues-unsubscribe@iceberg.apache.org
For additional commands, e-mail: issues-help@iceberg.apache.org


[GitHub] [iceberg] rdblue commented on a diff in pull request #5432: AES GCM Stream Spec

Posted by GitBox <gi...@apache.org>.
rdblue commented on code in PR #5432:
URL: https://github.com/apache/iceberg/pull/5432#discussion_r950909873


##########
format/gcm-stream-spec.md:
##########
@@ -0,0 +1,87 @@
+---
+title: "AES GCM Stream Spec"
+url: gcm-stream-spec
+toc: true
+disableSidebar: true
+---
+<!--
+ - Licensed to the Apache Software Foundation (ASF) under one or more
+ - contributor license agreements.  See the NOTICE file distributed with
+ - this work for additional information regarding copyright ownership.
+ - The ASF licenses this file to You 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.
+ -->
+
+# AES GCM Stream (AGS) file format extension
+
+## Background and Motivation
+
+Iceberg supports a number of data file formats. Two of these formats (Parquet and ORC) have built-in encryption capabilities, that allow to protect sensitive information in the data files. However, besides the data files, Iceberg tables also have metadata files, that keep sensitive information too (e.g., min/max values in manifest files, or bloom filter bitsets in puffin files). Metadata file formats (AVRO, JSON, Puffin) don't have encryption support.
+
+Moreover, with the exception of Parquet, no Iceberg data or metadata file format supports integrity verification, required for end-to-end tamper proofing of Iceberg tables.
+
+This document specifies details of a simple file format extension that adds encryption and tamper-proofing to any existing file format.
+
+## Goals
+
+* Metadata encryption: enable encryption of manifests, manifest lists, snapshots and stats.
+* Avro data encryption: enable encryption of data files in tables that use the Avro format.
+* Tamper proofing of Iceberg data and metadata files.
+
+## Overview
+
+The output stream, produced by a metadata or data writer, is split into equal-size blocks (plus residue). Each block is enciphered (encrypted/signed) with a given encryption key, and stored in a file in the AGS format. Upon reading, the stored cipherblocks are verified for integrity; then decrypted and passed to metadata or data readers.
+
+## Encryption algorithm
+
+AGS uses the standard AEG GCM cipher, and supports all AES key sizes: 128, 192 and 256 bits.
+
+AES GCM is an authenticated encryption. Besides data confidentiality (encryption), it supports two levels of integrity verification (authentication): of the data (default), and of the data combined with an optional AAD (“additional authenticated data”). An AAD is a free text to be authenticated, together with the data. The structure of AGS AADs is described below.
+
+AES GCM requires a unique vector to be provided for each encrypted block. In this document, the unique input to GCM encryption is called nonce (“number used once”). AGS encryption uses the RBG-based (random bit generator) nonce construction as defined in the section 8.2.2 of the NIST SP 800-38D document. For each encrypted block, AGS generates a unique nonce with a length of 12 bytes (96 bits).
+
+## Format specification
+
+### File structure
+
+The AGS-encrypted files have the following structure
+
+```
+Magic BlockLength CipherBlock₁ CipherBlock₂ ... CipherBlockₙ
+```
+
+where
+
+- `Magic` is four bytes 0x41, 0x47, 0x53, 0x31 ("AGS1", short for: AES GCM Stream, version 1)
+- `BlockLength` is four bytes (little endian) integer keeping the length of the equal-size split blocks before encryption. The length is specified in bytes.
+- `CipherBlockᵢ` is the i-th enciphered block in the file, with the structure defined below.
+
+### Cipher Block structure
+
+Cipher blocks have the following structure
+
+| nonce | ciphertext | tag |
+|-------|------------|-----|
+
+where
+
+- `nonce` is the AES GCM nonce, with a length of 12 bytes.
+- `ciphertext` is the encrypted block. Its length is identical to the length of the block before encryption ("plaintext"). The length of all plaintext blocks, except the last, is `BlockLength` bytes. The last block keeps the data residue, with a length <= `BlockLength`.
+- `tag` is the AES GCM tag, with a length of 16 bytes.
+
+AGS encrypts all blocks by the GCM cipher, without padding. The AES GCM cipher must be implemented by a cryptographic provider according to the NIST SP 800-38D specification. In AGS, an input to the GCM cipher is an AES encryption key, a nonce, a plaintext and an AAD (described below). The output is a ciphertext with the length equal to that of plaintext, and a 16-byte authentication tag used to verify the ciphertext and AAD integrity.
+
+### Additional Authenticated Data
+
+The AES GCM cipher protects against byte replacement inside a ciphertext block - but, without an AAD, it can't prevent replacement of one ciphertext block with another (encrypted with the same key). AGS leverages AADs to protect against swapping ciphertext blocks inside a file or between files. AGS can also protect against swapping full files - for example, replacement of a metadata file with an old version. AADs are built to reflects the identity of a file and of the blocks inside the file.
+
+AGS constructs a block AAD from two components: an AAD prefix - a string provided by Iceberg for the file (with the file ID), and an AAD suffix - the block sequence number in the file, as an int in a 4-byte little-endian form. The block AAD is a direct concatenation of the prefix and suffix parts.

Review Comment:
   Can you provide more context on how the AAD prefix is managed for the metadata tree?



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscribe@iceberg.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: issues-unsubscribe@iceberg.apache.org
For additional commands, e-mail: issues-help@iceberg.apache.org


[GitHub] [iceberg] rdblue commented on a diff in pull request #5432: AES GCM Stream Spec

Posted by GitBox <gi...@apache.org>.
rdblue commented on code in PR #5432:
URL: https://github.com/apache/iceberg/pull/5432#discussion_r950916081


##########
format/gcm-stream-spec.md:
##########
@@ -0,0 +1,87 @@
+---
+title: "AES GCM Stream Spec"
+url: gcm-stream-spec
+toc: true
+disableSidebar: true
+---
+<!--
+ - Licensed to the Apache Software Foundation (ASF) under one or more
+ - contributor license agreements.  See the NOTICE file distributed with
+ - this work for additional information regarding copyright ownership.
+ - The ASF licenses this file to You 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.
+ -->
+
+# AES GCM Stream (AGS) file format extension
+
+## Background and Motivation
+
+Iceberg supports a number of data file formats. Two of these formats (Parquet and ORC) have built-in encryption capabilities, that allow to protect sensitive information in the data files. However, besides the data files, Iceberg tables also have metadata files, that keep sensitive information too (e.g., min/max values in manifest files, or bloom filter bitsets in puffin files). Metadata file formats (AVRO, JSON, Puffin) don't have encryption support.
+
+Moreover, with the exception of Parquet, no Iceberg data or metadata file format supports integrity verification, required for end-to-end tamper proofing of Iceberg tables.
+
+This document specifies details of a simple file format extension that adds encryption and tamper-proofing to any existing file format.
+
+## Goals
+
+* Metadata encryption: enable encryption of manifests, manifest lists, snapshots and stats.
+* Avro data encryption: enable encryption of data files in tables that use the Avro format.
+* Tamper proofing of Iceberg data and metadata files.
+
+## Overview
+
+The output stream, produced by a metadata or data writer, is split into equal-size blocks (plus residue). Each block is enciphered (encrypted/signed) with a given encryption key, and stored in a file in the AGS format. Upon reading, the stored cipherblocks are verified for integrity; then decrypted and passed to metadata or data readers.
+
+## Encryption algorithm
+
+AGS uses the standard AEG GCM cipher, and supports all AES key sizes: 128, 192 and 256 bits.
+
+AES GCM is an authenticated encryption. Besides data confidentiality (encryption), it supports two levels of integrity verification (authentication): of the data (default), and of the data combined with an optional AAD (“additional authenticated data”). An AAD is a free text to be authenticated, together with the data. The structure of AGS AADs is described below.
+
+AES GCM requires a unique vector to be provided for each encrypted block. In this document, the unique input to GCM encryption is called nonce (“number used once”). AGS encryption uses the RBG-based (random bit generator) nonce construction as defined in the section 8.2.2 of the NIST SP 800-38D document. For each encrypted block, AGS generates a unique nonce with a length of 12 bytes (96 bits).
+
+## Format specification
+
+### File structure
+
+The AGS-encrypted files have the following structure
+
+```
+Magic BlockLength CipherBlock₁ CipherBlock₂ ... CipherBlockₙ
+```
+
+where
+
+- `Magic` is four bytes 0x41, 0x47, 0x53, 0x31 ("AGS1", short for: AES GCM Stream, version 1)
+- `BlockLength` is four bytes (little endian) integer keeping the length of the equal-size split blocks before encryption. The length is specified in bytes.
+- `CipherBlockᵢ` is the i-th enciphered block in the file, with the structure defined below.
+
+### Cipher Block structure
+
+Cipher blocks have the following structure
+
+| nonce | ciphertext | tag |
+|-------|------------|-----|

Review Comment:
   To be able to split formats like Avro that are splittable, we need to be able to go back and forth between offsets in the underlying data stream and in the AGS stream. I think that's possible since this has a strict format. The header structure is 8 bytes (4 magic + 4 block length) and then there is 24 bytes of overhead per CipherBlock (12 nonce + 12 tag).
   
   For any given offset in the underlying stream, we can find the block where it will be found by dividing by the block length:
   
   ```python
   def plain_block_index(offset, block_length):
       return offset // block_length
   ```
   
   Then we can skip to a given block:
   
   ```python
   def cipher_block_offset(block_index, block_length):
       return 8 + block_index * (24 + block_length)
   ```
   
   But the problem is that we don't get split offsets in the underlying file, we get split offsets in the AGS stream and need to figure out where in the underlying file those translate to, so that we don't have overlapping ranges that tasks are responsible for. We have a picture like this for a block size of 1024, 3 blocks, and a last block of size 553:
   
   |  | magic | block length | nonce-1 | ciphertext-1 | tag-1 | nonce-2 | ciphertext-2 | tag-2 | nonce-3 | ciphertext-3 | tag-3 | EOF |
   | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- |
   | AGS offset | 0 | 4 | 8 | 20 (to 1043) | 1044 | 1056 | 1068 (to 2091) | 2092 | 2104 | 2116 (to 2668) | 2669 | 2681 |
   | Stream offset |  |  |  | 0 (to 1023) |  |  | 1024 (to 2047) |  |  | 2048 (to 2601) |  | 2602 |
   
   To convert an AGS offset into a stream offset, I think we need to produce the the block index and an offset in that block. Producing the block index is the opposite of the `cipher_block_offset` function:
   
   ```python
   def cipher_block_index(cipher_offset, block_length):
       if (cipher_offset < 8):
           raise ValueError()
       return (cipher_offset - 8) // (block_length + 24)
   ```
   
   Then the offset in the plaintext block can be produced by subtracting the ciphertext offset from the start of the ciphertext block and some extra accounting:
   
   ```python
   def plaintext_block_offset(cipher_offset, block_length):
       block_index = cipher_block_index(cipher_offset, block_length)
       block_start = ciphertext_block_offset(block_index, block_length)
       local_offset = ciphertext_offset - block_start
       return local_offset if local_offset < block_length else block_length
   ```
   
   The check against `block_length` ensures that the local block offsets never overlap. Offsets that are between the ciphertext blocks (like 1048 in tag-1 for the example above) are mapped to the end of the plaintext block. This gives us a stable way to recover plaintext offsets.
   
   Using the plaintext offsets, I think we can reliably split AGS files that store Avro data:
   1. Convert AGS byte range splits into plaintext splits, removing any 0-byte splits (unlikely but possible)
   2. Implement an AGS stream that can seek to plaintext offsets (using the translation methods above)
   3. Pass the plaintext splits into the Avro reader with the plaintext seeking AGS stream
   
   @ggershinsky, what do you think?



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscribe@iceberg.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: issues-unsubscribe@iceberg.apache.org
For additional commands, e-mail: issues-help@iceberg.apache.org


[GitHub] [iceberg] rdblue commented on a diff in pull request #5432: AES GCM Stream Spec

Posted by GitBox <gi...@apache.org>.
rdblue commented on code in PR #5432:
URL: https://github.com/apache/iceberg/pull/5432#discussion_r950908755


##########
format/gcm-stream-spec.md:
##########
@@ -0,0 +1,87 @@
+---
+title: "AES GCM Stream Spec"
+url: gcm-stream-spec
+toc: true
+disableSidebar: true
+---
+<!--
+ - Licensed to the Apache Software Foundation (ASF) under one or more
+ - contributor license agreements.  See the NOTICE file distributed with
+ - this work for additional information regarding copyright ownership.
+ - The ASF licenses this file to You 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.
+ -->
+
+# AES GCM Stream (AGS) file format extension

Review Comment:
   Is AGS a common alias for AES GCM? I don't know about introducing a new acronym.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscribe@iceberg.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: issues-unsubscribe@iceberg.apache.org
For additional commands, e-mail: issues-help@iceberg.apache.org


[GitHub] [iceberg] rdblue commented on a diff in pull request #5432: AES GCM Stream Spec

Posted by GitBox <gi...@apache.org>.
rdblue commented on code in PR #5432:
URL: https://github.com/apache/iceberg/pull/5432#discussion_r950908856


##########
format/gcm-stream-spec.md:
##########
@@ -0,0 +1,87 @@
+---
+title: "AES GCM Stream Spec"
+url: gcm-stream-spec
+toc: true
+disableSidebar: true
+---
+<!--
+ - Licensed to the Apache Software Foundation (ASF) under one or more
+ - contributor license agreements.  See the NOTICE file distributed with
+ - this work for additional information regarding copyright ownership.
+ - The ASF licenses this file to You 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.
+ -->
+
+# AES GCM Stream (AGS) file format extension
+
+## Background and Motivation
+
+Iceberg supports a number of data file formats. Two of these formats (Parquet and ORC) have built-in encryption capabilities, that allow to protect sensitive information in the data files. However, besides the data files, Iceberg tables also have metadata files, that keep sensitive information too (e.g., min/max values in manifest files, or bloom filter bitsets in puffin files). Metadata file formats (AVRO, JSON, Puffin) don't have encryption support.
+
+Moreover, with the exception of Parquet, no Iceberg data or metadata file format supports integrity verification, required for end-to-end tamper proofing of Iceberg tables.
+
+This document specifies details of a simple file format extension that adds encryption and tamper-proofing to any existing file format.
+
+## Goals
+
+* Metadata encryption: enable encryption of manifests, manifest lists, snapshots and stats.
+* Avro data encryption: enable encryption of data files in tables that use the Avro format.

Review Comment:
   Is the intent to make the streams splittable? I think that's a key feature that we should call out as either supported as a goal or not.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscribe@iceberg.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: issues-unsubscribe@iceberg.apache.org
For additional commands, e-mail: issues-help@iceberg.apache.org


[GitHub] [iceberg] rdblue commented on a diff in pull request #5432: AES GCM Stream Spec

Posted by GitBox <gi...@apache.org>.
rdblue commented on code in PR #5432:
URL: https://github.com/apache/iceberg/pull/5432#discussion_r950908755


##########
format/gcm-stream-spec.md:
##########
@@ -0,0 +1,87 @@
+---
+title: "AES GCM Stream Spec"
+url: gcm-stream-spec
+toc: true
+disableSidebar: true
+---
+<!--
+ - Licensed to the Apache Software Foundation (ASF) under one or more
+ - contributor license agreements.  See the NOTICE file distributed with
+ - this work for additional information regarding copyright ownership.
+ - The ASF licenses this file to You 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.
+ -->
+
+# AES GCM Stream (AGS) file format extension

Review Comment:
   Is AGS a common alias for AES GCM? I don't think that we should introduce a new acronym.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscribe@iceberg.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: issues-unsubscribe@iceberg.apache.org
For additional commands, e-mail: issues-help@iceberg.apache.org


[GitHub] [iceberg] RussellSpitzer commented on a diff in pull request #5432: AES GCM Stream Spec

Posted by GitBox <gi...@apache.org>.
RussellSpitzer commented on code in PR #5432:
URL: https://github.com/apache/iceberg/pull/5432#discussion_r937958733


##########
format/gcm-stream-spec.md:
##########
@@ -0,0 +1,89 @@
+---
+title: "AES GCM Stream Spec"
+url: gcm-stream-spec
+toc: true
+disableSidebar: true
+---
+<!--
+ - Licensed to the Apache Software Foundation (ASF) under one or more
+ - contributor license agreements.  See the NOTICE file distributed with
+ - this work for additional information regarding copyright ownership.
+ - The ASF licenses this file to You 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.
+ -->
+
+# AES GCM Stream (AGS) file format extension
+
+## Background and Motivation
+
+Iceberg supports a number of data file formats. Two of these formats (Parquet and ORC) have built-in encryption capabilities, that allow to protect sensitive information in the data files. However, besides the data files, Iceberg tables also have metadata files, that keep sensitive information too (e.g., min/max values in manifest files, or bloom filter bitsets in puffin files). Metadata file formats (AVRO, JSON, Puffin) don't have encryption support.
+
+Moreover, with the exception of Parquet, no Iceberg data or metadata file format supports integrity verification, required for end-to-end tamper proofing of Iceberg tables.
+
+This document specifies details of a simple file format extension that adds encryption and tamper-proofing to any existing file format.
+
+## Goals
+
+* Metadata encryption: enable encryption of manifests, manifest lists, snapshots and stats.
+* Avro data encryption: enable encryption of data files in tables that use the Avro format.
+* Tamper proofing of Iceberg data and metadata files.
+
+## Technical approach

Review Comment:
   For the spec I don't think we need information about the reference implementation but that's just me.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscribe@iceberg.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: issues-unsubscribe@iceberg.apache.org
For additional commands, e-mail: issues-help@iceberg.apache.org


[GitHub] [iceberg] rdblue commented on a diff in pull request #5432: AES GCM Stream Spec

Posted by GitBox <gi...@apache.org>.
rdblue commented on code in PR #5432:
URL: https://github.com/apache/iceberg/pull/5432#discussion_r1015859348


##########
format/gcm-stream-spec.md:
##########
@@ -0,0 +1,87 @@
+---
+title: "AES GCM Stream Spec"
+url: gcm-stream-spec
+toc: true
+disableSidebar: true
+---
+<!--
+ - Licensed to the Apache Software Foundation (ASF) under one or more
+ - contributor license agreements.  See the NOTICE file distributed with
+ - this work for additional information regarding copyright ownership.
+ - The ASF licenses this file to You 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.
+ -->
+
+# AES GCM Stream (AGS) file format extension
+
+## Background and Motivation
+
+Iceberg supports a number of data file formats. Two of these formats (Parquet and ORC) have built-in encryption capabilities, that allow to protect sensitive information in the data files. However, besides the data files, Iceberg tables also have metadata files, that keep sensitive information too (e.g., min/max values in manifest files, or bloom filter bitsets in puffin files). Metadata file formats (AVRO, JSON, Puffin) don't have encryption support.
+
+Moreover, with the exception of Parquet, no Iceberg data or metadata file format supports integrity verification, required for end-to-end tamper proofing of Iceberg tables.
+
+This document specifies details of a simple file format extension that adds encryption and tamper-proofing to any existing file format.
+
+## Goals
+
+* Metadata encryption: enable encryption of manifests, manifest lists, snapshots and stats.
+* Avro data encryption: enable encryption of data files in tables that use the Avro format.
+* Tamper proofing of Iceberg data and metadata files.
+
+## Overview
+
+The output stream, produced by a metadata or data writer, is split into equal-size blocks (plus residue). Each block is enciphered (encrypted/signed) with a given encryption key, and stored in a file in the AGS format. Upon reading, the stored cipherblocks are verified for integrity; then decrypted and passed to metadata or data readers.
+
+## Encryption algorithm
+
+AGS uses the standard AEG GCM cipher, and supports all AES key sizes: 128, 192 and 256 bits.
+
+AES GCM is an authenticated encryption. Besides data confidentiality (encryption), it supports two levels of integrity verification (authentication): of the data (default), and of the data combined with an optional AAD (“additional authenticated data”). An AAD is a free text to be authenticated, together with the data. The structure of AGS AADs is described below.
+
+AES GCM requires a unique vector to be provided for each encrypted block. In this document, the unique input to GCM encryption is called nonce (“number used once”). AGS encryption uses the RBG-based (random bit generator) nonce construction as defined in the section 8.2.2 of the NIST SP 800-38D document. For each encrypted block, AGS generates a unique nonce with a length of 12 bytes (96 bits).
+
+## Format specification
+
+### File structure
+
+The AGS-encrypted files have the following structure
+
+```
+Magic BlockLength CipherBlock₁ CipherBlock₂ ... CipherBlockₙ
+```
+
+where
+
+- `Magic` is four bytes 0x41, 0x47, 0x53, 0x31 ("AGS1", short for: AES GCM Stream, version 1)
+- `BlockLength` is four bytes (little endian) integer keeping the length of the equal-size split blocks before encryption. The length is specified in bytes.
+- `CipherBlockᵢ` is the i-th enciphered block in the file, with the structure defined below.
+
+### Cipher Block structure
+
+Cipher blocks have the following structure
+
+| nonce | ciphertext | tag |
+|-------|------------|-----|
+
+where
+
+- `nonce` is the AES GCM nonce, with a length of 12 bytes.
+- `ciphertext` is the encrypted block. Its length is identical to the length of the block before encryption ("plaintext"). The length of all plaintext blocks, except the last, is `BlockLength` bytes. The last block keeps the data residue, with a length <= `BlockLength`.
+- `tag` is the AES GCM tag, with a length of 16 bytes.
+
+AGS encrypts all blocks by the GCM cipher, without padding. The AES GCM cipher must be implemented by a cryptographic provider according to the NIST SP 800-38D specification. In AGS, an input to the GCM cipher is an AES encryption key, a nonce, a plaintext and an AAD (described below). The output is a ciphertext with the length equal to that of plaintext, and a 16-byte authentication tag used to verify the ciphertext and AAD integrity.
+
+### Additional Authenticated Data
+
+The AES GCM cipher protects against byte replacement inside a ciphertext block - but, without an AAD, it can't prevent replacement of one ciphertext block with another (encrypted with the same key). AGS leverages AADs to protect against swapping ciphertext blocks inside a file or between files. AGS can also protect against swapping full files - for example, replacement of a metadata file with an old version. AADs are built to reflects the identity of a file and of the blocks inside the file.
+
+AGS constructs a block AAD from two components: an AAD prefix - a string provided by Iceberg for the file (with the file ID), and an AAD suffix - the block sequence number in the file, as an int in a 4-byte little-endian form. The block AAD is a direct concatenation of the prefix and suffix parts.

Review Comment:
   Sounds fine. We'll need to solve that problem eventually though.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscribe@iceberg.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: issues-unsubscribe@iceberg.apache.org
For additional commands, e-mail: issues-help@iceberg.apache.org


[GitHub] [iceberg] rdblue commented on a diff in pull request #5432: AES GCM Stream Spec

Posted by GitBox <gi...@apache.org>.
rdblue commented on code in PR #5432:
URL: https://github.com/apache/iceberg/pull/5432#discussion_r950908532


##########
format/gcm-stream-spec.md:
##########
@@ -0,0 +1,87 @@
+---
+title: "AES GCM Stream Spec"
+url: gcm-stream-spec
+toc: true
+disableSidebar: true
+---
+<!--
+ - Licensed to the Apache Software Foundation (ASF) under one or more
+ - contributor license agreements.  See the NOTICE file distributed with
+ - this work for additional information regarding copyright ownership.
+ - The ASF licenses this file to You 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.
+ -->
+
+# AES GCM Stream (AGS) file format extension
+
+## Background and Motivation
+
+Iceberg supports a number of data file formats. Two of these formats (Parquet and ORC) have built-in encryption capabilities, that allow to protect sensitive information in the data files. However, besides the data files, Iceberg tables also have metadata files, that keep sensitive information too (e.g., min/max values in manifest files, or bloom filter bitsets in puffin files). Metadata file formats (AVRO, JSON, Puffin) don't have encryption support.
+
+Moreover, with the exception of Parquet, no Iceberg data or metadata file format supports integrity verification, required for end-to-end tamper proofing of Iceberg tables.
+
+This document specifies details of a simple file format extension that adds encryption and tamper-proofing to any existing file format.

Review Comment:
   I think this should be more clear that the proposal is to encrypt an entire stream, which will prevent skipping in the underlying file.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscribe@iceberg.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: issues-unsubscribe@iceberg.apache.org
For additional commands, e-mail: issues-help@iceberg.apache.org


[GitHub] [iceberg] ggershinsky commented on a diff in pull request #5432: AES GCM Stream Spec

Posted by GitBox <gi...@apache.org>.
ggershinsky commented on code in PR #5432:
URL: https://github.com/apache/iceberg/pull/5432#discussion_r963355163


##########
format/gcm-stream-spec.md:
##########
@@ -0,0 +1,87 @@
+---
+title: "AES GCM Stream Spec"
+url: gcm-stream-spec
+toc: true
+disableSidebar: true
+---
+<!--
+ - Licensed to the Apache Software Foundation (ASF) under one or more
+ - contributor license agreements.  See the NOTICE file distributed with
+ - this work for additional information regarding copyright ownership.
+ - The ASF licenses this file to You 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.
+ -->
+
+# AES GCM Stream (AGS) file format extension
+
+## Background and Motivation
+
+Iceberg supports a number of data file formats. Two of these formats (Parquet and ORC) have built-in encryption capabilities, that allow to protect sensitive information in the data files. However, besides the data files, Iceberg tables also have metadata files, that keep sensitive information too (e.g., min/max values in manifest files, or bloom filter bitsets in puffin files). Metadata file formats (AVRO, JSON, Puffin) don't have encryption support.
+
+Moreover, with the exception of Parquet, no Iceberg data or metadata file format supports integrity verification, required for end-to-end tamper proofing of Iceberg tables.
+
+This document specifies details of a simple file format extension that adds encryption and tamper-proofing to any existing file format.
+
+## Goals
+
+* Metadata encryption: enable encryption of manifests, manifest lists, snapshots and stats.
+* Avro data encryption: enable encryption of data files in tables that use the Avro format.
+* Tamper proofing of Iceberg data and metadata files.
+
+## Overview
+
+The output stream, produced by a metadata or data writer, is split into equal-size blocks (plus residue). Each block is enciphered (encrypted/signed) with a given encryption key, and stored in a file in the AGS format. Upon reading, the stored cipherblocks are verified for integrity; then decrypted and passed to metadata or data readers.
+
+## Encryption algorithm
+
+AGS uses the standard AEG GCM cipher, and supports all AES key sizes: 128, 192 and 256 bits.
+
+AES GCM is an authenticated encryption. Besides data confidentiality (encryption), it supports two levels of integrity verification (authentication): of the data (default), and of the data combined with an optional AAD (“additional authenticated data”). An AAD is a free text to be authenticated, together with the data. The structure of AGS AADs is described below.
+
+AES GCM requires a unique vector to be provided for each encrypted block. In this document, the unique input to GCM encryption is called nonce (“number used once”). AGS encryption uses the RBG-based (random bit generator) nonce construction as defined in the section 8.2.2 of the NIST SP 800-38D document. For each encrypted block, AGS generates a unique nonce with a length of 12 bytes (96 bits).
+
+## Format specification
+
+### File structure
+
+The AGS-encrypted files have the following structure
+
+```
+Magic BlockLength CipherBlock₁ CipherBlock₂ ... CipherBlockₙ
+```
+
+where
+
+- `Magic` is four bytes 0x41, 0x47, 0x53, 0x31 ("AGS1", short for: AES GCM Stream, version 1)
+- `BlockLength` is four bytes (little endian) integer keeping the length of the equal-size split blocks before encryption. The length is specified in bytes.
+- `CipherBlockᵢ` is the i-th enciphered block in the file, with the structure defined below.
+
+### Cipher Block structure
+
+Cipher blocks have the following structure
+
+| nonce | ciphertext | tag |
+|-------|------------|-----|
+
+where
+
+- `nonce` is the AES GCM nonce, with a length of 12 bytes.
+- `ciphertext` is the encrypted block. Its length is identical to the length of the block before encryption ("plaintext"). The length of all plaintext blocks, except the last, is `BlockLength` bytes. The last block keeps the data residue, with a length <= `BlockLength`.

Review Comment:
   AGS should not hit EOF. It gets the length of the encrypted file from the source InputFile object, then reads the block side, and knows from the start the number/size of the encrypted blocks.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscribe@iceberg.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: issues-unsubscribe@iceberg.apache.org
For additional commands, e-mail: issues-help@iceberg.apache.org


[GitHub] [iceberg] rdblue commented on a diff in pull request #5432: AES GCM Stream Spec

Posted by GitBox <gi...@apache.org>.
rdblue commented on code in PR #5432:
URL: https://github.com/apache/iceberg/pull/5432#discussion_r1015856676


##########
format/gcm-stream-spec.md:
##########
@@ -0,0 +1,87 @@
+---
+title: "AES GCM Stream Spec"
+url: gcm-stream-spec
+toc: true
+disableSidebar: true
+---
+<!--
+ - Licensed to the Apache Software Foundation (ASF) under one or more
+ - contributor license agreements.  See the NOTICE file distributed with
+ - this work for additional information regarding copyright ownership.
+ - The ASF licenses this file to You 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.
+ -->
+
+# AES GCM Stream (AGS) file format extension
+
+## Background and Motivation
+
+Iceberg supports a number of data file formats. Two of these formats (Parquet and ORC) have built-in encryption capabilities, that allow to protect sensitive information in the data files. However, besides the data files, Iceberg tables also have metadata files, that keep sensitive information too (e.g., min/max values in manifest files, or bloom filter bitsets in puffin files). Metadata file formats (AVRO, JSON, Puffin) don't have encryption support.
+
+Moreover, with the exception of Parquet, no Iceberg data or metadata file format supports integrity verification, required for end-to-end tamper proofing of Iceberg tables.
+
+This document specifies details of a simple file format extension that adds encryption and tamper-proofing to any existing file format.

Review Comment:
   This overview should state that the stream is still seekable and can be used with splittable formats like Avro.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscribe@iceberg.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: issues-unsubscribe@iceberg.apache.org
For additional commands, e-mail: issues-help@iceberg.apache.org


[GitHub] [iceberg] ggershinsky commented on pull request #5432: AES GCM Stream Spec

Posted by GitBox <gi...@apache.org>.
ggershinsky commented on PR #5432:
URL: https://github.com/apache/iceberg/pull/5432#issuecomment-1310159553

   @rdblue I've sent a commit that addresses the review comments. 
   Regarding the magic string - it's 4-byte long, so I've kept "AGS1" (only) there; but if it's a problem, I can replace it with any suggested alternative.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscribe@iceberg.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: issues-unsubscribe@iceberg.apache.org
For additional commands, e-mail: issues-help@iceberg.apache.org


[GitHub] [iceberg] rdblue commented on a diff in pull request #5432: AES GCM Stream Spec

Posted by GitBox <gi...@apache.org>.
rdblue commented on code in PR #5432:
URL: https://github.com/apache/iceberg/pull/5432#discussion_r950909597


##########
format/gcm-stream-spec.md:
##########
@@ -0,0 +1,87 @@
+---
+title: "AES GCM Stream Spec"
+url: gcm-stream-spec
+toc: true
+disableSidebar: true
+---
+<!--
+ - Licensed to the Apache Software Foundation (ASF) under one or more
+ - contributor license agreements.  See the NOTICE file distributed with
+ - this work for additional information regarding copyright ownership.
+ - The ASF licenses this file to You 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.
+ -->
+
+# AES GCM Stream (AGS) file format extension
+
+## Background and Motivation
+
+Iceberg supports a number of data file formats. Two of these formats (Parquet and ORC) have built-in encryption capabilities, that allow to protect sensitive information in the data files. However, besides the data files, Iceberg tables also have metadata files, that keep sensitive information too (e.g., min/max values in manifest files, or bloom filter bitsets in puffin files). Metadata file formats (AVRO, JSON, Puffin) don't have encryption support.
+
+Moreover, with the exception of Parquet, no Iceberg data or metadata file format supports integrity verification, required for end-to-end tamper proofing of Iceberg tables.
+
+This document specifies details of a simple file format extension that adds encryption and tamper-proofing to any existing file format.
+
+## Goals
+
+* Metadata encryption: enable encryption of manifests, manifest lists, snapshots and stats.
+* Avro data encryption: enable encryption of data files in tables that use the Avro format.
+* Tamper proofing of Iceberg data and metadata files.
+
+## Overview
+
+The output stream, produced by a metadata or data writer, is split into equal-size blocks (plus residue). Each block is enciphered (encrypted/signed) with a given encryption key, and stored in a file in the AGS format. Upon reading, the stored cipherblocks are verified for integrity; then decrypted and passed to metadata or data readers.
+
+## Encryption algorithm
+
+AGS uses the standard AEG GCM cipher, and supports all AES key sizes: 128, 192 and 256 bits.
+
+AES GCM is an authenticated encryption. Besides data confidentiality (encryption), it supports two levels of integrity verification (authentication): of the data (default), and of the data combined with an optional AAD (“additional authenticated data”). An AAD is a free text to be authenticated, together with the data. The structure of AGS AADs is described below.
+
+AES GCM requires a unique vector to be provided for each encrypted block. In this document, the unique input to GCM encryption is called nonce (“number used once”). AGS encryption uses the RBG-based (random bit generator) nonce construction as defined in the section 8.2.2 of the NIST SP 800-38D document. For each encrypted block, AGS generates a unique nonce with a length of 12 bytes (96 bits).
+
+## Format specification
+
+### File structure
+
+The AGS-encrypted files have the following structure
+
+```
+Magic BlockLength CipherBlock₁ CipherBlock₂ ... CipherBlockₙ
+```
+
+where
+
+- `Magic` is four bytes 0x41, 0x47, 0x53, 0x31 ("AGS1", short for: AES GCM Stream, version 1)
+- `BlockLength` is four bytes (little endian) integer keeping the length of the equal-size split blocks before encryption. The length is specified in bytes.
+- `CipherBlockᵢ` is the i-th enciphered block in the file, with the structure defined below.
+
+### Cipher Block structure
+
+Cipher blocks have the following structure
+
+| nonce | ciphertext | tag |
+|-------|------------|-----|
+
+where
+
+- `nonce` is the AES GCM nonce, with a length of 12 bytes.
+- `ciphertext` is the encrypted block. Its length is identical to the length of the block before encryption ("plaintext"). The length of all plaintext blocks, except the last, is `BlockLength` bytes. The last block keeps the data residue, with a length <= `BlockLength`.

Review Comment:
   This seems a bit awkward because streaming through the file will eventually hit a partial block and EOF. Then the reader would need to backtrack and separate the last 12 bytes read for the tag. The reader could also keep track of position in the file and stop before reading the tag and hitting EOF, but then that requires position tracking and logic.
   
   I don't see a good way around this, but I thought I'd raise it in case anyone else does.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscribe@iceberg.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: issues-unsubscribe@iceberg.apache.org
For additional commands, e-mail: issues-help@iceberg.apache.org


[GitHub] [iceberg] rdblue commented on a diff in pull request #5432: AES GCM Stream Spec

Posted by GitBox <gi...@apache.org>.
rdblue commented on code in PR #5432:
URL: https://github.com/apache/iceberg/pull/5432#discussion_r950916081


##########
format/gcm-stream-spec.md:
##########
@@ -0,0 +1,87 @@
+---
+title: "AES GCM Stream Spec"
+url: gcm-stream-spec
+toc: true
+disableSidebar: true
+---
+<!--
+ - Licensed to the Apache Software Foundation (ASF) under one or more
+ - contributor license agreements.  See the NOTICE file distributed with
+ - this work for additional information regarding copyright ownership.
+ - The ASF licenses this file to You 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.
+ -->
+
+# AES GCM Stream (AGS) file format extension
+
+## Background and Motivation
+
+Iceberg supports a number of data file formats. Two of these formats (Parquet and ORC) have built-in encryption capabilities, that allow to protect sensitive information in the data files. However, besides the data files, Iceberg tables also have metadata files, that keep sensitive information too (e.g., min/max values in manifest files, or bloom filter bitsets in puffin files). Metadata file formats (AVRO, JSON, Puffin) don't have encryption support.
+
+Moreover, with the exception of Parquet, no Iceberg data or metadata file format supports integrity verification, required for end-to-end tamper proofing of Iceberg tables.
+
+This document specifies details of a simple file format extension that adds encryption and tamper-proofing to any existing file format.
+
+## Goals
+
+* Metadata encryption: enable encryption of manifests, manifest lists, snapshots and stats.
+* Avro data encryption: enable encryption of data files in tables that use the Avro format.
+* Tamper proofing of Iceberg data and metadata files.
+
+## Overview
+
+The output stream, produced by a metadata or data writer, is split into equal-size blocks (plus residue). Each block is enciphered (encrypted/signed) with a given encryption key, and stored in a file in the AGS format. Upon reading, the stored cipherblocks are verified for integrity; then decrypted and passed to metadata or data readers.
+
+## Encryption algorithm
+
+AGS uses the standard AEG GCM cipher, and supports all AES key sizes: 128, 192 and 256 bits.
+
+AES GCM is an authenticated encryption. Besides data confidentiality (encryption), it supports two levels of integrity verification (authentication): of the data (default), and of the data combined with an optional AAD (“additional authenticated data”). An AAD is a free text to be authenticated, together with the data. The structure of AGS AADs is described below.
+
+AES GCM requires a unique vector to be provided for each encrypted block. In this document, the unique input to GCM encryption is called nonce (“number used once”). AGS encryption uses the RBG-based (random bit generator) nonce construction as defined in the section 8.2.2 of the NIST SP 800-38D document. For each encrypted block, AGS generates a unique nonce with a length of 12 bytes (96 bits).
+
+## Format specification
+
+### File structure
+
+The AGS-encrypted files have the following structure
+
+```
+Magic BlockLength CipherBlock₁ CipherBlock₂ ... CipherBlockₙ
+```
+
+where
+
+- `Magic` is four bytes 0x41, 0x47, 0x53, 0x31 ("AGS1", short for: AES GCM Stream, version 1)
+- `BlockLength` is four bytes (little endian) integer keeping the length of the equal-size split blocks before encryption. The length is specified in bytes.
+- `CipherBlockᵢ` is the i-th enciphered block in the file, with the structure defined below.
+
+### Cipher Block structure
+
+Cipher blocks have the following structure
+
+| nonce | ciphertext | tag |
+|-------|------------|-----|

Review Comment:
   To be able to split formats like Avro that are splittable, we need to be able to go back and forth between offsets in the underlying data stream and in the AGS stream. I think that's possible since this has a strict format. The header structure is 8 bytes (4 magic + 4 block length) and then there is 24 bytes of overhead per CipherBlock (12 nonce + 12 tag).
   
   For any given offset in the underlying stream, we can find the block where it will be found by dividing by the block length:
   
   ```python
   def plain_block_index(plain_offset, block_length):
       return offset // block_length
   ```
   
   Then we can skip to a given block:
   
   ```python
   def cipher_block_offset(block_index, block_length):
       return 8 + block_index * (24 + block_length)
   ```
   
   But the problem is that we don't get split offsets in the underlying file, we get split offsets in the AGS stream and need to figure out where in the underlying file those translate to, so that we don't have overlapping ranges that tasks are responsible for. We have a picture like this for a block size of 1024, 3 blocks, and a last block of size 553:
   
   |  | magic | block length | nonce-1 | ciphertext-1 | tag-1 | nonce-2 | ciphertext-2 | tag-2 | nonce-3 | ciphertext-3 | tag-3 | EOF |
   | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- |
   | AGS offset | 0 | 4 | 8 | 20 (to 1043) | 1044 | 1056 | 1068 (to 2091) | 2092 | 2104 | 2116 (to 2668) | 2669 | 2681 |
   | Stream offset |  |  |  | 0 (to 1023) |  |  | 1024 (to 2047) |  |  | 2048 (to 2601) |  | 2602 |
   
   To convert an AGS offset into a stream offset, I think we need to produce the the block index and an offset in that block. Producing the block index is the opposite of the `cipher_block_offset` function:
   
   ```python
   def cipher_block_index(cipher_offset, block_length):
       if (cipher_offset < 8):
           raise ValueError()
       return (cipher_offset - 8) // (block_length + 24)
   ```
   
   Then the offset in the plaintext block can be produced by subtracting the ciphertext offset from the start of the ciphertext block and some extra accounting:
   
   ```python
   def plaintext_block_offset(cipher_offset, block_length):
       block_index = cipher_block_index(cipher_offset, block_length)
       block_start = cipher_block_offset(block_index, block_length)
       local_offset = ciphert_offset - block_start
       return local_offset if local_offset < block_length else block_length
   ```
   
   The check against `block_length` ensures that the local block offsets never overlap. Offsets that are between the ciphertext blocks (like 1048 in tag-1 for the example above) are mapped to the end of the plaintext block. This gives us a stable way to recover plaintext offsets.
   
   Using the plaintext offsets, I think we can reliably split AGS files that store Avro data:
   1. Convert AGS byte range splits into plaintext splits, removing any 0-byte splits (unlikely but possible)
   2. Implement an AGS stream that can seek to plaintext offsets (using the translation methods above)
   3. Pass the plaintext splits into the Avro reader with the plaintext seeking AGS stream
   
   @ggershinsky, what do you think?



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscribe@iceberg.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: issues-unsubscribe@iceberg.apache.org
For additional commands, e-mail: issues-help@iceberg.apache.org


[GitHub] [iceberg] rdblue commented on pull request #5432: AES GCM Stream Spec

Posted by GitBox <gi...@apache.org>.
rdblue commented on PR #5432:
URL: https://github.com/apache/iceberg/pull/5432#issuecomment-1328351721

   Looks great. I merged this. Thanks, @ggershinsky!


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscribe@iceberg.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: issues-unsubscribe@iceberg.apache.org
For additional commands, e-mail: issues-help@iceberg.apache.org


[GitHub] [iceberg] rdblue merged pull request #5432: AES GCM Stream Spec

Posted by GitBox <gi...@apache.org>.
rdblue merged PR #5432:
URL: https://github.com/apache/iceberg/pull/5432


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscribe@iceberg.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: issues-unsubscribe@iceberg.apache.org
For additional commands, e-mail: issues-help@iceberg.apache.org