콘텐츠로 이동
getnextpdf.com

Enterprise 에디션

스테가노그래피 — 심층 참조

이 심층 레퍼런스는 NextPDF Enterprise 스테가노그래피 채널을 문서화합니다. 이 채널은 TJ 텍스트 표시 배열의 숫자형 커닝 조정값 안에 암호화된 페이로드를 숨깁니다. 네 개의 공개 심볼을 가집니다: SteganographyEncoder, SteganographyDecoder, SteganographyConfig, SteganographyCapacity. 인코더는 HKDF-SHA-256으로 키를 유도하고, AEAD 암호로 페이로드를 암호화하며, 위치별 커닝 오프셋을 반환합니다. 디코더는 관측된 조정값 또는 원시 콘텐츠 스트림으로부터 그 과정을 역으로 수행합니다.

이 채널은 내부 문서 유출 추적을 위해 설계되었습니다. 적대적 환경에 대응하는 등급의 스테가노그래피가 아닙니다. 인코딩된 데이터는 인쇄 후 스캔, PDF 변환, 재선형화, 콘텐츠 스트림 재작성, 또는 커닝을 정규화하는 모든 작업에 의해 파괴될 수 있습니다. NextPDF는 이 채널에 대해 어떠한 인증도 보유하지 않으며 부여하지도 않습니다. 이 페이지는 적합성이 아니라 기능을 기술합니다.

이 기능은 NextPDF Enterprise (nextpdf/enterprise)에 포함되어 제공되며 Enterprise 등급 라이선스 봉투로 활성화됩니다. 해당 자격이 없는 배포에서는 기능의 클래스가 로드되지 않습니다. 에디션 비교 및 라이선스 구매.

이 채널은 네 개의 final 클래스를 노출합니다. SteganographyConfig 생성자와 그 effectiveMaxOffset 접근자를 제외하면 모든 진입점은 public static입니다. 보조 타입인 NextPDF\Enterprise\Security\Steganography\SteganographyEncryptionException은 인코더에 의해 던져지며, 호출자가 생성하는 타입이 아닙니다.

심볼매개변수기본 동작반환던지거나 실패하는 조건비고
SteganographyEncoder::encode$payload, $text, $fontKey, $metrics (FontMetrics), $secretKey, $config (SteganographyConfig)$payload[]를 반환; 키 강도를 단언; 암호화; 위치별 커닝 오프셋을 계산.array<int, float> (position => 1/1000 em 단위 조정값, AFM 관례)InvalidArgumentException (하한 미만 키); OverflowException (텍스트가 2문자 미만이거나 페이로드가 용량 초과); SteganographyEncryptionException (AEAD 실패)결과를 NextPDF\Content\TextRenderer::buildTjArrayOperator()에 전달하십시오. API는 AFM 관례 조정값을 반환하며, buildTjArrayOperator()가 PDF TJ 숫자 변환을 수행합니다 (ISO 32000-2는 현재 위치에서 숫자를 뺍니다). 수동 콘텐츠 스트림 작성자는 그 부호 관례를 반드시 보존해야 합니다.
SteganographyEncoder::assertSecretKeyStrength$secretKey하한보다 짧은 키를 거부.voidInvalidArgumentException (하한 미만 키)쓰기 경로 공유 가드로, 읽기 경로에도 동일하게 반영됩니다.
SteganographyEncoder::MIN_SECRET_KEY_LENGTH상수바이트 단위 128비트 키 길이 하한.int (16)해당 없음라이브러리는 엔트로피가 아니라 길이를 강제합니다.
SteganographyDecoder::decode$observedAdjustments, $text, $fontKey, $metrics (FontMetrics), $secretKey, $config (SteganographyConfig)키 강도를 단언; 편차를 양자화; 블롭을 재구성; AEAD 복호화.`stringnull(페이로드, 또는 잘못된 키나 페이로드 없음일 때null`)InvalidArgumentException (하한 미만 키)
SteganographyDecoder::decodeFromContentStream$contentStream, $fontKey, $metrics (FontMetrics), $secretKey, $config (SteganographyConfig)스트림을 토큰화하고, TJ 배열로부터 텍스트와 조정값을 재구성한 뒤 decode에 위임.`stringnull(페이로드, 또는TJ텍스트가 없거나 복호화 실패 시null`)InvalidArgumentException (하한 미만 키, decode를 경유)
SteganographyConfig::__construct$bitDepth, $maxAdjustmentEmRatio, $cipher, $requirePdfACompatibility각 인수의 도메인을 검증; 불변 값 객체를 생성.SteganographyConfig 인스턴스InvalidArgumentException (유효하지 않은 $bitDepth, $maxAdjustmentEmRatio, 또는 $cipher)readonly 클래스; 네 개의 인수는 public으로 승격된 프로퍼티입니다.
SteganographyConfig::effectiveMaxOffset없음$maxAdjustmentEmRatio * 1000을 반환하며, PDF/A 호환성이 요청되면 절반으로 줄입니다.float (1/1000 em 단위 오프셋)해당 없음절반으로 줄이는 것은 폭 불일치 탐지 위험을 낮춥니다.
SteganographyConfig::CRYPTO_OVERHEAD상수페이로드당 고정 암호화 오버헤드(바이트).int (32)해당 없음4바이트 길이, 12바이트 논스, 16바이트 태그.
SteganographyCapacity::calculate$text, $config (SteganographyConfig)오버헤드를 제외한, 텍스트의 사용 가능한 페이로드 바이트를 계산.int (텍스트가 너무 짧으면 0)해당 없음용량은 positions * bitDepth / 8에서 오버헤드를 뺀 값입니다.
SteganographyCapacity::minimumTextLength$payloadBytes, $config (SteganographyConfig)페이로드에 필요한 최소 UTF-8 문자 수를 계산.int (문자 수)해당 없음calculate의 역함수.

각각의 출처 정보와 함께 원문 그대로의 시그니처가 아래에 이어집니다.

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

인코더는 $text를 UTF-8 문자로 분할하고 연속된 문자 쌍마다 하나의 위치를 형성합니다. 각 위치는 $config->bitDepth 비트를 담으며, 이는 1 또는 2입니다. 페이로드는 먼저 암호화되고, 블롭으로 직렬화된 다음, 비트 시퀀스로 변환됩니다. 각 위치는 자신의 비트를 해당 문자 쌍의 자연 커닝 값에 더해지는 작은 음이 아닌 오프셋으로 인코딩합니다.

오프셋은 유효 최대 오프셋의 일부입니다. 유효 최대 오프셋은 $maxAdjustmentEmRatio * 1000 디자인 단위이며, $requirePdfACompatibility가 true이면 절반으로 줄어듭니다. 자연 커닝은 FontMetrics::getKernPair를 통해 $metrics에서 읽습니다. 반환되는 맵은 희소합니다: 최종 조정값이 정확히 0인 위치는 생략됩니다.

암호화는 HKDF-SHA-256을 사용하여 32바이트 키를 유도합니다. HKDF 솔트는 비밀이 아닌 $fontKey이고 info 레이블은 고정 상수입니다. 따라서 호출자의 $secretKey가 유일한 기밀성 경계입니다. AEAD 암호는 $config->cipher로 선택되는 aes-256-gcm 또는 chacha20-poly1305이며, 새로운 12바이트 논스와 16바이트 태그로 openssl_encrypt를 통해 실행됩니다. 직렬화된 블롭은 4바이트 빅엔디언 길이, 12바이트 논스, 암호문, 16바이트 태그로 구성됩니다. 이 고정 오버헤드가 CRYPTO_OVERHEAD이며, 32바이트입니다.

디코더는 이 변환을 역으로 수행합니다. 관측된 각 조정값과 자연 커닝의 편차를 계산하고, 유효 최대 오프셋으로 정규화한 뒤, 가장 가까운 레벨로 양자화합니다. 블롭을 재조립하고, 길이 헤더를 검증한 다음, openssl_decrypt를 호출합니다. 잘못된 키, 누락된 페이로드, 또는 손상된 조정값은 AEAD 인증을 실패하게 만들며, 디코더는 null을 반환합니다. decodeFromContentStream은 먼저 NextPDF\Pro\Projection\ContentProjectionWriter::tokenize로 원시 스트림을 토큰화하고, 각 TJ 배열로부터 텍스트와 숫자 조정값을 재구성한 뒤, decode에 위임합니다.

SteganographyCapacity::calculateCRYPTO_OVERHEAD를 뺀 뒤 텍스트와 구성에 대한 사용 가능한 페이로드 크기를 보고하며, 텍스트가 너무 짧으면 0을 반환합니다. SteganographyCapacity::minimumTextLength는 그 역함수로, 요청한 크기의 페이로드를 수용할 수 있는 가장 작은 UTF-8 문자 수입니다.

  • $payloadencode에서 빈 맵을 반환합니다. 어떤 바이트도 기록되지 않으며, 키 강도 가드에도 도달하지 않습니다.
  • 비어 있지 않은 페이로드의 경우, 문자가 두 개 미만인 $textencode에서 OverflowException을 발생시킵니다 (빈 페이로드는 길이 검사 이전에 []로 단락 처리됨). 동일한 텍스트는 decode에서 null을, SteganographyCapacity::calculate에서 0을 반환합니다.
  • 텍스트 용량보다 큰 $payload는 어떤 조정값도 방출되기 전에 OverflowException을 발생시킵니다.
  • MIN_SECRET_KEY_LENGTH(16바이트)보다 짧은 $secretKey는 쓰기 경로와 읽기 경로 모두에서 InvalidArgumentException을 발생시킵니다. 이것은 계약 위반으로, 정상적인 잘못된 키 미스와는 구별됩니다.
  • 잘못된 키, 손상된 조정값 집합, 또는 잘린 블롭은 예외가 아니라 AEAD 인증 실패를 통해 decodenull을 반환하게 만듭니다.
  • 희소한 $observedAdjustments 맵에서 누락된 위치는 추출 중 0 편차로 취급됩니다.
  • decodeFromContentStream은 스트림에 TJ 텍스트가 없으면 null을 반환합니다.
  • 이 채널은 설계상 취약합니다. 인쇄 후 스캔, PDF 변환, 재선형화, 콘텐츠 스트림 재작성, 또는 커닝 정규화가 인코딩된 데이터를 파괴할 수 있습니다. 적대적 용도나 아카이브 용도에는 적합하지 않습니다.

이 채널은 키 유도에 HKDF-SHA-256을, 기밀성과 무결성에 하나의 AEAD 암호를 사용합니다. NextPDF는 이 채널에 대해 어떠한 FIPS 검증도 보유하지 않으며 주장하지도 않습니다. 모듈은 FIPS 프로파일을 강제하지 않으며, 암호 선택은 $config->cipher를 통한 호출자의 결정입니다. aes-256-gcm은 Galois/Counter Mode의 AES로, NIST SP 800-38D §2에 따라 CMVP 하에서 적합성이 검증되는 승인된 128비트 블록 암호 위에 구축된 인증 암호화 모드입니다. chacha20-poly1305는 NIST 운영 모드 권장 사항으로 정의되어 있지 않으므로, FIPS로 제약된 OpenSSL 프로바이더는 이를 거부합니다. 그러면 openssl_encrypt가 false를 반환하고 인코더는 SteganographyEncryptionException을 발생시킵니다. 배포가 FIPS 요구 사항을 충족하는지 여부는 검증된 프로바이더에 대한 운영자의 판단이며, NextPDF의 단언이 아닙니다.

이 삽입은 TJ 텍스트 표시 배열에 숫자 요소를 기록합니다. ISO 32000-2:2020 §9.4.3에 따라, TJ 배열은 텍스트를 표시하고 숫자 요소가 글리프 위치를 조정하게 하며, 그 숫자는 텍스트 공간 단위의 천분의 일로 표현되고 현재 위치에서 뺍니다. 글리프가 그려진 후 텍스트 행렬은 결합된 변위만큼 이동하므로, 위치 지정 숫자는 후속 글리프의 배치를 이동시킵니다 — ISO 32000-2:2020 §9.4.4. 이 채널은 동일한 1/1000 em (AFM) 관례로 자연 커닝 값에 오프셋을 더하며, 여기서 음수 값은 자간을 좁힙니다.

AEAD 근거는 프리미티브 선택에 국한됩니다: aes-256-gcm은 NIST SP 800-38D §2의 GCM 모드에 해당합니다. 그 참조는 알고리즘을 식별하는 것이며, 이 채널에 대한 검증이 아닙니다.

모든 조항은 의역된 것이며, NextPDF는 규범적 텍스트를 재현하지 않습니다. NextPDF는 이 채널에 대해 어떠한 스테가노그래피, 암호학, 또는 PDF 적합성 주장도 하지 않습니다. TJ 위치 지정 모델과의 구조적 정렬은 기능 진술이지 인증이 아닙니다. 견고성 고지는 유효합니다: 이 채널은 내부 유출 추적을 위한 것이며, 적대적 환경에 대응하는 등급이 아닙니다.

  • 진입점은 SteganographyConfig 생성자와 effectiveMaxOffset를 제외하면 NextPDF\Enterprise\Security\Steganographypublic static 메서드입니다.
  • SteganographyConfigfinal readonly 값 객체입니다. 네 개의 프로퍼티는 생성 후 불변이며, 인수 도메인은 생성자에서 검증됩니다: $bitDepth는 1 또는 2, $maxAdjustmentEmRatio(0, 0.05] 범위, $cipheraes-256-gcm 또는 chacha20-poly1305입니다.
  • encode 출력은 NextPDF\Content\TextRenderer::buildTjArrayOperator에 의해 소비됩니다. 커닝 쌍은 NextPDF\Typography\FontMetrics에서 옵니다. 콘텐츠 스트림 디코딩은 NextPDF\Pro\Projection\ContentProjectionWriter를 통해 읽으며 스트림을 변형하지 않습니다.
  • 키 길이 하한은 진입점에서 강제되고 비공개 암호 경계에서 다시 단언되므로, 어떤 내부 경로도 약한 키로 HKDF에 도달할 수 없습니다. 라이브러리는 엔트로피가 아니라 길이를 강제합니다. 높은 엔트로피의 키 재료를 공급하는 것은 통합자의 책임입니다.
  • CRYPTO_OVERHEAD(32바이트)는 페이로드당 고정 비용이며 SteganographyCapacity::calculate에 의해 이미 차감됩니다.
  • 문서화된 since는 집계된 Enterprise 표면에 대해 3.1.0입니다. SteganographyEncryptionExceptionRuntimeException을 확장하므로, 일반 런타임 타입을 잡는 호출 지점은 계속 동작합니다.

이 페이지는 외부에서 관측 가능한 동작과 지원되는 공개 API 표면만을 문서화합니다. 내부 네임스페이스 경로, 헬퍼 클래스, 메커니즘 테이블, 런북 파일명, 티켓 접두사는 범위에 포함되지 않습니다.