You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
73 lines
2.3 KiB
73 lines
2.3 KiB
package capsule
|
|
|
|
import (
|
|
"fmt"
|
|
"math/bits"
|
|
)
|
|
|
|
// Padding is the padding rule of the payload of a format 2 capsule, sealed in
|
|
// key 7 of CONTROL_CBOR (spec §29.1, §31). No code stands for no padding.
|
|
type Padding uint8
|
|
|
|
// Padding rules of format 2 (spec §29.1).
|
|
const (
|
|
// Bloque256 pads the content to the next multiple of 256 bytes, and to
|
|
// at least 256.
|
|
Bloque256 Padding = 1
|
|
// Reforzado pads to the larger of Bloque256 and Padmé. It is the rule
|
|
// Encrypt uses by default, as spec §29.1 asks of the official SDK.
|
|
Reforzado Padding = 2
|
|
)
|
|
|
|
// MaxPayloadLength is L_MAX = 2^53 - 2^46, the largest content length a
|
|
// format 2 capsule can seal: the largest L for which both rules give a P of
|
|
// at most 2^53 - 1 (spec §29.1).
|
|
const MaxPayloadLength = 1<<53 - 1<<46
|
|
|
|
func (p Padding) String() string {
|
|
switch p {
|
|
case Bloque256:
|
|
return "bloque256"
|
|
case Reforzado:
|
|
return "reforzado"
|
|
}
|
|
return fmt.Sprintf("padding(%d)", uint8(p))
|
|
}
|
|
|
|
func (p Padding) valid() bool { return p == Bloque256 || p == Reforzado }
|
|
|
|
// PaddedLength returns P = rule(L), the exact length of the plaintext of
|
|
// PAYLOAD_AGE in a format 2 capsule whose content is l bytes long (spec
|
|
// §29.1). The arithmetic is exact and on 64-bit integers only, never a
|
|
// floating-point logarithm or 32-bit operations.
|
|
func PaddedLength(l uint64, p Padding) (uint64, error) {
|
|
if !p.valid() {
|
|
return 0, fmt.Errorf("capsule: padding code %d is not defined", uint8(p))
|
|
}
|
|
if l > MaxPayloadLength {
|
|
return 0, fmt.Errorf("capsule: content of %d bytes exceeds L_MAX = %d", l, uint64(MaxPayloadLength))
|
|
}
|
|
if l <= 256 {
|
|
return 256, nil
|
|
}
|
|
block := (l + 255) &^ 255
|
|
if p == Bloque256 {
|
|
return block, nil
|
|
}
|
|
// Padmé: keep the S + 1 most significant bits of L and round up the
|
|
// others, with E = floor(log2 L) and S = floor(log2 E) + 1.
|
|
e := uint64(bits.Len64(l) - 1)
|
|
s := uint64(bits.Len64(e))
|
|
mask := uint64(1)<<(e-s) - 1
|
|
return max(block, (l+mask)&^mask), nil
|
|
}
|
|
|
|
// PayloadAgeLength returns the length of a PAYLOAD_AGE whose plaintext is n
|
|
// bytes long: the 184 bytes of an age header with one X25519 stanza and the
|
|
// nonce, the plaintext, and the 16-byte tag of each 64 KiB STREAM chunk, at
|
|
// least one (spec §62.1, informative note).
|
|
func PayloadAgeLength(n uint64) uint64 {
|
|
chunks := max(1, (n+65535)/65536)
|
|
return 184 + n + 16*chunks
|
|
}
|