Bỏ qua để đến nội dung
getnextpdf.com

Enterprise phiên bản

Steganography — Tài liệu tham chiếu chuyên sâu

Tham chiếu chuyên sâu này ghi lại kênh steganographic của NextPDF Enterprise. Kênh này ẩn một payload đã mã hóa bên trong các điều chỉnh kern dạng số của một mảng hiển thị văn bản TJ. Nó có bốn ký hiệu công khai: SteganographyEncoder, SteganographyDecoder, SteganographyConfig, và SteganographyCapacity. Bộ mã hóa dẫn xuất một khóa bằng HKDF-SHA-256, mã hóa payload bằng một cipher AEAD, và trả về các độ dời kern theo từng vị trí. Bộ giải mã đảo ngược quy trình từ các điều chỉnh quan sát được hoặc từ một content stream thô.

Kênh này được thiết kế để truy vết rò rỉ tài liệu nội bộ. Nó không phải là steganography cấp độ chống đối thủ. Dữ liệu đã được mã hóa có thể bị phá hủy bởi in-rồi-quét, chuyển đổi PDF, tái tuyến tính hóa, viết lại content stream, hoặc bất kỳ thao tác nào chuẩn hóa kerning. NextPDF không nắm giữ chứng nhận nào cho kênh này và cũng không cấp chứng nhận nào. Trang này nêu năng lực, không phải sự tuân thủ.

Năng lực này được cung cấp trong NextPDF Enterprise (nextpdf/enterprise) và được kích hoạt bằng một envelope giấy phép hạng Enterprise. Một triển khai không có quyền đó sẽ không tải các lớp của năng lực này. So sánh các phiên bản và nhận giấy phép.

Kênh này phơi bày bốn lớp final. Tất cả các điểm vào đều là public static, ngoại trừ hàm khởi tạo SteganographyConfig và accessor effectiveMaxOffset của nó. Lớp hỗ trợ NextPDF\Enterprise\Security\Steganography\SteganographyEncryptionException được ném ra bởi bộ mã hóa; nó không phải là kiểu do bên gọi khởi tạo.

Ký hiệuTham sốHành vi mặc địnhTrả vềNém ra hoặc thất bại vớiGhi chú
SteganographyEncoder::encode$payload, $text, $fontKey, $metrics (FontMetrics), $secretKey, $config (SteganographyConfig)$payload rỗng trả về []; kiểm định độ mạnh của khóa; mã hóa; tính các độ dời kern theo từng vị trí.array<int, float> (vị trí => điều chỉnh theo 1/1000 em, quy ước AFM)InvalidArgumentException (khóa dưới ngưỡng sàn); OverflowException (văn bản dưới 2 ký tự, hoặc payload vượt dung lượng); SteganographyEncryptionException (lỗi AEAD)Truyền kết quả cho NextPDF\Content\TextRenderer::buildTjArrayOperator(). API trả về các điều chỉnh theo quy ước AFM; buildTjArrayOperator() thực hiện việc chuyển đổi số TJ của PDF (ISO 32000-2 trừ số này khỏi vị trí hiện tại). Người viết content stream thủ công phải bảo toàn quy ước dấu đó.
SteganographyEncoder::assertSecretKeyStrength$secretKeyTừ chối một khóa ngắn hơn ngưỡng sàn.voidInvalidArgumentException (khóa dưới ngưỡng sàn)Bộ bảo vệ trên đường ghi dùng chung, được phản chiếu trên đường đọc.
SteganographyEncoder::MIN_SECRET_KEY_LENGTHhằng sốNgưỡng sàn độ dài khóa 128-bit tính bằng byte.int (16)Không áp dụngThư viện bắt buộc độ dài, không phải entropy.
SteganographyDecoder::decode$observedAdjustments, $text, $fontKey, $metrics (FontMetrics), $secretKey, $config (SteganographyConfig)Kiểm định độ mạnh của khóa; lượng tử hóa các độ lệch; dựng lại blob; giải mã AEAD.`stringnull(payload, hoặcnull` khi sai khóa hoặc không có payload)InvalidArgumentException (khóa dưới ngưỡng sàn)
SteganographyDecoder::decodeFromContentStream$contentStream, $fontKey, $metrics (FontMetrics), $secretKey, $config (SteganographyConfig)Token hóa stream, tái dựng văn bản và các điều chỉnh từ các mảng TJ, rồi ủy thác cho decode.`stringnull(payload, hoặcnullkhi không có văn bảnTJ` hoặc giải mã thất bại)InvalidArgumentException (khóa dưới ngưỡng sàn, thông qua decode)
SteganographyConfig::__construct$bitDepth, $maxAdjustmentEmRatio, $cipher, $requirePdfACompatibilityKiểm định miền của từng đối số; tạo ra một value object bất biến.Instance SteganographyConfigInvalidArgumentException ($bitDepth, $maxAdjustmentEmRatio, hoặc $cipher không hợp lệ)Lớp readonly; bốn đối số là các thuộc tính public được promote.
SteganographyConfig::effectiveMaxOffsetkhông cóTrả về $maxAdjustmentEmRatio * 1000, chia đôi khi yêu cầu tương thích PDF/A.float (độ dời theo 1/1000 em)Không áp dụngViệc chia đôi làm giảm rủi ro phát hiện qua sai lệch bề rộng.
SteganographyConfig::CRYPTO_OVERHEADhằng sốChi phí mã hóa cố định theo từng payload tính bằng byte.int (32)Không áp dụng4-byte độ dài, 12-byte nonce, 16-byte tag.
SteganographyCapacity::calculate$text, $config (SteganographyConfig)Tính số byte payload khả dụng cho văn bản, sau khi trừ overhead.int (0 khi văn bản quá ngắn)Không áp dụngDung lượng là positions * bitDepth / 8 trừ overhead.
SteganographyCapacity::minimumTextLength$payloadBytes, $config (SteganographyConfig)Tính số ký tự UTF-8 tối thiểu cho một payload.int (số ký tự)Không áp dụngNghịch đảo của calculate.

Các chữ ký nguyên văn theo sau, mỗi chữ ký kèm xuất xứ mã nguồn.

public static function encode(
string $payload,
string $text,
string $fontKey,
FontMetrics $metrics,
string $secretKey,
SteganographyConfig $config = new SteganographyConfig(),
): array
public static function assertSecretKeyStrength(string $secretKey): void
public const int MIN_SECRET_KEY_LENGTH = 16;
public static function decode(
array $observedAdjustments,
string $text,
string $fontKey,
FontMetrics $metrics,
string $secretKey,
SteganographyConfig $config = new SteganographyConfig(),
): ?string
public static function decodeFromContentStream(
string $contentStream,
string $fontKey,
FontMetrics $metrics,
string $secretKey,
SteganographyConfig $config = new SteganographyConfig(),
): ?string
public function __construct(
public int $bitDepth = 1,
public float $maxAdjustmentEmRatio = 0.02,
public string $cipher = 'aes-256-gcm',
public bool $requirePdfACompatibility = false,
)
public function effectiveMaxOffset(): float
public const int CRYPTO_OVERHEAD = 32;
public static function calculate(
string $text,
SteganographyConfig $config = new SteganographyConfig(),
): int
public static function minimumTextLength(
int $payloadBytes,
SteganographyConfig $config = new SteganographyConfig(),
): int

Bộ mã hóa tách $text thành các ký tự UTF-8 và tạo một vị trí cho mỗi cặp ký tự liên tiếp. Mỗi vị trí mang $config->bitDepth bit, tức là một hoặc hai. Payload trước tiên được mã hóa, rồi được tuần tự hóa thành một blob, rồi được chuyển đổi thành một chuỗi bit. Mỗi vị trí mã hóa các bit của nó thành một độ dời nhỏ không âm được cộng vào giá trị kern tự nhiên của cặp ký tự đó.

Độ dời là một phần của độ dời tối đa hiệu dụng. Độ dời tối đa hiệu dụng là $maxAdjustmentEmRatio * 1000 đơn vị thiết kế, chia đôi khi $requirePdfACompatibility là true. Giá trị kern tự nhiên được đọc từ $metrics thông qua FontMetrics::getKernPair. Bản đồ trả về là thưa: một vị trí có điều chỉnh cuối cùng đúng bằng không sẽ bị bỏ qua.

Việc mã hóa dùng HKDF-SHA-256 để dẫn xuất một khóa 32-byte. Salt của HKDF là $fontKey không bí mật và nhãn info là một hằng số cố định. Do đó $secretKey của bên gọi là ranh giới bảo mật duy nhất. Cipher AEAD là aes-256-gcm hoặc chacha20-poly1305, được chọn qua $config->cipher, chạy qua openssl_encrypt với một nonce 12-byte mới và một tag 16-byte. Blob đã tuần tự hóa gồm một độ dài big-endian 4-byte, nonce 12-byte, ciphertext, và tag 16-byte; overhead cố định này là CRYPTO_OVERHEAD, tức là 32 byte.

Bộ giải mã đảo ngược phép biến đổi. Nó tính độ lệch của mỗi điều chỉnh quan sát được so với kern tự nhiên, chuẩn hóa theo độ dời tối đa hiệu dụng, và lượng tử hóa về mức gần nhất. Nó lắp ráp lại blob, kiểm định header độ dài, và gọi openssl_decrypt. Một khóa sai, một payload thiếu, hoặc các điều chỉnh bị hỏng khiến việc xác thực AEAD thất bại, và bộ giải mã trả về null. decodeFromContentStream trước tiên token hóa stream thô bằng NextPDF\Pro\Projection\ContentProjectionWriter::tokenize, tái dựng văn bản và các điều chỉnh dạng số từ mỗi mảng TJ, rồi ủy thác cho decode.

SteganographyCapacity::calculate báo cáo kích thước payload khả dụng cho một văn bản và cấu hình, sau khi trừ CRYPTO_OVERHEAD; nó trả về không khi văn bản quá ngắn. SteganographyCapacity::minimumTextLength là nghịch đảo: số ký tự UTF-8 nhỏ nhất chấp nhận được một payload có kích thước yêu cầu.

  • Một $payload rỗng trả về một bản đồ rỗng từ encode; không byte nào được ghi, và bộ bảo vệ độ mạnh khóa không được chạm tới.
  • Đối với một payload không rỗng, một $text có ít hơn hai ký tự làm phát sinh OverflowException trong encode (một payload rỗng đoản mạch về [] trước phép kiểm tra độ dài); cùng văn bản đó cho ra null trong decode và không trong SteganographyCapacity::calculate.
  • Một $payload lớn hơn dung lượng của văn bản làm phát sinh OverflowException trước khi bất kỳ điều chỉnh nào được phát ra.
  • Một $secretKey ngắn hơn MIN_SECRET_KEY_LENGTH (16 byte) làm phát sinh InvalidArgumentException trên cả đường ghi lẫn đường đọc. Đây là một vi phạm hợp đồng, khác với một lần trượt khóa sai thông thường.
  • Một khóa sai, một tập điều chỉnh bị hỏng, hoặc một blob bị cắt cụt khiến decode trả về null thông qua thất bại xác thực AEAD, không phải một exception.
  • Các vị trí vắng mặt trong một bản đồ $observedAdjustments thưa được xem là độ lệch bằng không trong quá trình trích xuất.
  • decodeFromContentStream trả về null khi stream không chứa văn bản TJ.
  • Kênh này mong manh theo thiết kế. In-rồi-quét, chuyển đổi PDF, tái tuyến tính hóa, viết lại content stream, hoặc chuẩn hóa kerning có thể phá hủy dữ liệu đã mã hóa. Nó không phù hợp cho mục đích chống đối thủ hay lưu trữ dài hạn.

Kênh này dùng HKDF-SHA-256 cho việc dẫn xuất khóa và một cipher AEAD cho bảo mật và toàn vẹn. NextPDF không nắm giữ chứng nhận FIPS nào cho kênh này và cũng không tuyên bố có. Module không bắt buộc một hồ sơ FIPS; việc chọn cipher là quyết định của bên gọi thông qua $config->cipher. aes-256-gcm là AES ở chế độ Galois/Counter Mode, một chế độ mã hóa có xác thực được xây dựng trên một block cipher 128-bit đã được phê duyệt mà sự tuân thủ của nó được kiểm định dưới CMVP, theo NIST SP 800-38D §2. chacha20-poly1305 không được định nghĩa bởi một khuyến nghị chế độ vận hành của NIST, nên một provider OpenSSL bị ràng buộc FIPS sẽ từ chối nó; openssl_encrypt khi đó trả về false và bộ mã hóa làm phát sinh SteganographyEncryptionException. Việc một triển khai có đáp ứng yêu cầu FIPS hay không là sự xác định của người vận hành đối với provider đã được kiểm định của họ, không phải một khẳng định của NextPDF.

Việc nhúng ghi các phần tử số vào một mảng hiển thị văn bản TJ. Theo ISO 32000-2:2020 §9.4.3, một mảng TJ hiển thị văn bản và cho phép một phần tử số điều chỉnh vị trí glyph; số này được biểu diễn theo phần nghìn của một đơn vị không gian văn bản và được trừ khỏi vị trí hiện tại. Sau khi một glyph được vẽ, ma trận văn bản được tịnh tiến theo độ dịch chuyển tổng hợp, nên một số định vị làm dời vị trí đặt của các glyph tiếp theo — ISO 32000-2:2020 §9.4.4. Kênh này cộng các độ dời của nó vào các giá trị kern tự nhiên theo cùng quy ước 1/1000 em (AFM), trong đó một giá trị âm làm thu hẹp khoảng cách.

Cơ sở về AEAD chỉ giới hạn ở việc chọn nguyên thủy: aes-256-gcm tương ứng với chế độ GCM của NIST SP 800-38D §2. Tham chiếu đó xác định một thuật toán; nó không phải là một sự kiểm định cho kênh này.

Tất cả các điều khoản đều được diễn giải; NextPDF không tái tạo văn bản quy phạm. NextPDF không đưa ra tuyên bố tuân thủ nào về steganography, mật mã, hay PDF cho kênh này. Sự khớp về mặt cấu trúc với mô hình định vị TJ là một phát biểu về năng lực, không phải một chứng nhận. Lời công bố về độ bền vẫn giữ nguyên: kênh này dành cho việc truy vết rò rỉ nội bộ, và nó không đạt cấp độ chống đối thủ.

  • Các điểm vào là các phương thức public static trong NextPDF\Enterprise\Security\Steganography, ngoại trừ hàm khởi tạo SteganographyConfigeffectiveMaxOffset.
  • SteganographyConfig là một value object final readonly. Bốn thuộc tính của nó là bất biến sau khi khởi tạo, và các miền đối số của nó được kiểm định trong hàm khởi tạo: $bitDepth là 1 hoặc 2, $maxAdjustmentEmRatio nằm trong (0, 0.05], và $cipheraes-256-gcm hoặc chacha20-poly1305.
  • Đầu ra của encode được tiêu thụ bởi NextPDF\Content\TextRenderer::buildTjArrayOperator. Các cặp kern đến từ NextPDF\Typography\FontMetrics. Việc giải mã content stream đọc thông qua NextPDF\Pro\Projection\ContentProjectionWriter và không biến đổi stream.
  • Ngưỡng sàn độ dài khóa được bắt buộc tại điểm vào và được tái kiểm định tại ranh giới mật mã riêng tư, nên không đường đi nội bộ nào có thể chạm tới HKDF với một khóa yếu. Thư viện bắt buộc độ dài, không phải entropy; việc cung cấp vật liệu khóa có entropy cao là trách nhiệm của người tích hợp.
  • CRYPTO_OVERHEAD (32 byte) là chi phí cố định theo từng payload và đã được SteganographyCapacity::calculate trừ sẵn.
  • Phiên bản since được ghi là 3.1.0 cho bề mặt Enterprise được tổng hợp. SteganographyEncryptionException mở rộng RuntimeException, nên các call site bắt kiểu runtime chung sẽ tiếp tục hoạt động.

Trang này chỉ ghi lại hành vi có thể quan sát được từ bên ngoài và bề mặt API công khai được hỗ trợ. Các đường dẫn namespace nội bộ, lớp trợ giúp, bảng cơ chế, tên tệp runbook, và tiền tố ticket đều nằm ngoài phạm vi.