콘텐츠로 이동
getnextpdf.com

Enterprise 에디션

디지털 워터마킹 및 스테가노그래피 임베딩

NextPDF Enterprise는 문자 쌍 사이의 간격에 작고 통제된 조정을 가함으로써 숨겨진 암호화 페이로드를 생성된 PDF에 임베딩합니다. 페이로드 — 일반적으로 수신자별 식별자 — 와 시크릿 키를 제공하면, 인코더는 페이로드를 텍스트의 자연스러운 커닝으로부터의 감지할 수 없는 편차로 기록합니다. 동일한 키가 주어진 일치 디코더는 페이로드를 복원합니다. 이 페이지는 동작 수준입니다. 인코더가 무엇을 기록하는지, 사용하는 암호화, 그리고 이 기법의 경계를 명시합니다.

의도된 용도는 내부 문서 유출 추적입니다. 통제된 문서가 유출되면, 복원된 마커가 수신자 사본을 식별합니다. 이는 적대적 스테가노그래피가 아니며 임의의 처리를 거쳐 생존한다는 보장도 아닙니다.

전제 조건은 프런트 매터에 명시되어 있으며 전제 조건에서 반복됩니다.

이 역량은 NextPDF Enterprise(nextpdf/enterprise)에 포함되며 Enterprise 등급 라이선스 엔벌로프로 활성화됩니다. 그러한 자격이 없는 배포는 이 역량의 클래스를 로드하지 않습니다. 이 역량은 문서 생성 중 전적으로 인프로세스로 실행됩니다. 어떤 문서 콘텐츠도 호스트를 벗어나지 않습니다. 에디션 비교 및 라이선스 받기.

커닝 배열로 그려진 PDF 텍스트는 글리프 사이에 수치 조정을 담습니다. 인코더는 각 조정 위치를 몇 비트의 캐리어로 취급합니다.

  1. 페이로드를 연관 데이터를 갖는 인증 암호화(AEAD) 암호 — 기본값은 AES-256-GCM, 또는 ChaCha20-Poly1305 — 로 암호화합니다. AEAD는 기밀성과 무결성을 모두 제공하므로, 변조된 캐리어는 잘못된 페이로드를 조용히 산출하는 대신 복호화에 실패합니다.
  2. HMAC 기반 키 파생 함수(HKDF)와 SHA-256을 사용하여 시크릿 키와 폰트 키로부터 32바이트 암호화 키를 파생합니다. HKDF는 입력 키 자료로부터 고정 길이 의사 무작위 키를 추출한 다음, 이를 필요한 길이로 확장합니다. RFC 5869 §2를 따릅니다.
  3. 암호화마다 새로운 무작위 12바이트 초기화 벡터(IV)를 생성합니다. AES-GCM은 주어진 키에 대해 IV가 고유할 것을 요구하며, 그렇지 않으면 인증 보증이 손실됩니다. NIST SP 800-38D §5.2.1을 따릅니다.
  4. 암호화된 바이트를 비트 시퀀스로 매핑하고 비트를 사용 가능한 문자 쌍 위치에 분배하며, 위치당 1비트 또는 2비트를 인코딩합니다. 자연스러운 커닝에 더하는 편차는 em의 구성 가능한 비율로 제한됩니다 — 시각적으로 감지할 수 없을 만큼 작습니다.

디코더는 그 과정을 역으로 수행합니다. 콘텐츠 스트림에서 커닝 조정을 읽고, 자연스러운 커닝을 빼고, 편차를 비트로 양자화하고, 암호화된 블롭을 재조립하고, 동일한 키로 복호화합니다. 키가 잘못되었거나 캐리어가 파괴되었으면, 복호화는 잘못된 페이로드 대신 아무것도 반환하지 않습니다.

용량은 텍스트 길이에 따라 확장됩니다. 각 문자 쌍 위치는 1비트 또는 2비트를 담으므로, 페이로드는 텍스트가 제공하는 위치에 맞아야 합니다. 페이로드가 용량을 초과하면 인코더는 타입이 지정된 오버플로 오류를 발생시킵니다.

PDF/A 호환 모드는 검증기의 너비 허용 임계값 아래에 머물기 위해 최대 편차를 절반으로 줄여, 용량을 더 엄격한 적합성과 맞바꿉니다.

핵심이 되는 선택은 마커를 가시적 오버레이나 메타데이터 필드가 아니라 커닝에 숨기는 것입니다. 메타데이터 마커는 제거하기 쉽고, 가시적 스탬프는 페이지를 변경합니다. 대신 커닝 편차는 수신자가 반드시 유지해야 하는 텍스트 안에 실려 감지되지 않은 채 남습니다. 인증 암호화가 두 번째 기둥입니다. 변조되거나 부분적인 캐리어는 인증에 실패하므로, 디코더는 잘못된 수신자 대신 아무것도 반환하지 않습니다. 키는 HKDF로 폰트별로 파생되어, 마커를 단순한 공유 시크릿이 아니라 문서 맥락에 결합합니다. 정직한 견고성 공개가 여기서 직접 뒤따릅니다. 마커는 일반적인 재배포는 견디지만 고의적인 콘텐츠 스트림 재작성은 견디지 못하므로, 명시된 범위는 적대적 스테가노그래피가 아니라 내부 유출 추적입니다.

설계 배경: 편집(redaction)은 검은 사각형이 아닙니다.

  1. NextPDF Core와 Enterprise 패키지를 설치하고 활성 Enterprise 라이선스를 보유합니다.
  2. 커닝 쌍 메트릭을 노출하는 폰트로 문서를 생성합니다. 인코더는 폰트 메트릭에서 자연스러운 커닝을 읽습니다.
  3. 시크릿 키를 소스가 아니라 시크릿 매니저에서 제공합니다. 디코딩에는 동일한 키가 필요합니다.
  4. 용량 및 적합성 요구에 따라 비트 깊이(위치당 1비트 또는 2비트)와 PDF/A 호환성이 필요한지를 결정합니다.

인코딩 구성은 불변이며 생성 시점에 검증됩니다.

  • 비트 깊이 — 문자 쌍 위치당 1비트 또는 2비트입니다. 더 높은 깊이는 더 많은 용량을 주지만 더 큰 편차를 만듭니다.
  • 최대 조정 비율 — em의 비율로서의 편차 상한이며, 한정된 범위 안에 있습니다. 더 큰 값은 더 많은 여유를 주지만 가시성 위험이 있습니다.
  • 암호 — AES-256-GCM(기본값) 또는 ChaCha20-Poly1305입니다. 둘 다 AEAD입니다.
  • PDF/A 호환성 — 활성화되면 유효 최대 편차를 절반으로 줄입니다.

인코딩과 디코딩에 동일한 구성을 사용하십시오. 불일치는 복원된 페이로드를 산출하지 않습니다.

  1. 시크릿 매니저에서 시크릿 키를 읽습니다.
  2. 인코딩 구성(비트 깊이, 편차 비율, 암호, PDF/A 플래그)을 빌드합니다.
  3. 렌더링하려는 텍스트에 대한 커닝 조정을 계산하며, 페이로드, 텍스트, 폰트 키, 폰트 메트릭, 시크릿 키, 그리고 구성을 전달합니다.
  4. 텍스트 런을 기록할 때 반환된 조정을 적용하여 마커가 생성 중에 임베딩되도록 합니다.
  5. 유출된 사본을 추적하려면, 동일한 폰트 키, 폰트 메트릭, 시크릿 키, 그리고 구성으로 의심 문서의 콘텐츠 스트림에 디코더를 실행하고 복원된 페이로드를 읽습니다.
examples/enterprise/steganography-capacity-guard.php
<?php
declare(strict_types=1);
require_once __DIR__ . '/../../vendor/autoload.php';
/**
* Reject a payload that cannot fit the carrier text before encoding.
*
* Each letter-pair position carries $bitDepth bits. Guarding capacity up
* front turns an unencodable payload into a clear caller-side error instead
* of relying on the encoder's overflow exception alone.
*
* @param non-empty-string $payload The bytes to embed (already minimal).
* @param positive-int $textLength The character count of the carrier text.
* @param int<1, 2> $bitDepth Bits encoded per letter-pair position.
*
* @throws \OverflowException When the payload cannot fit the available positions.
*/
function assertPayloadFits(string $payload, int $textLength, int $bitDepth): void
{
$positions = $textLength - 1;
$capacityBytes = \intdiv($positions * $bitDepth, 8);
if (\strlen($payload) > $capacityBytes) {
throw new \OverflowException(\sprintf(
'Payload of %d bytes exceeds carrier capacity of %d bytes.',
\strlen($payload),
$capacityBytes,
));
}
}
examples/enterprise/steganography-decode-guarded.php
<?php
declare(strict_types=1);
require_once __DIR__ . '/../../vendor/autoload.php';
use NextPDF\Enterprise\Security\Steganography\SteganographyDecoder;
use NextPDF\Enterprise\Security\Steganography\SteganographyConfig;
use NextPDF\Typography\FontMetrics;
use Psr\Log\LoggerInterface;
final readonly class LeakTracer
{
public function __construct(private LoggerInterface $logger) {}
/**
* Recover the embedded marker from a suspect document's content stream.
*
* Decoding returns null on a wrong key or a destroyed carrier rather than
* a wrong payload, so the caller treats null as "no marker recovered".
*
* @param string $contentStream The suspect content-stream bytes.
* @param non-empty-string $fontKey The font key used at generation.
* @param FontMetrics $metrics Font metrics with kerning pairs.
* @param string $secretKey The same secret key used to encode.
* @param SteganographyConfig $config The same configuration used to encode.
*
* @return string|null The recovered marker, or null when none is found.
*/
public function trace(
string $contentStream,
string $fontKey,
FontMetrics $metrics,
string $secretKey,
SteganographyConfig $config,
): ?string {
$marker = SteganographyDecoder::decodeFromContentStream(
$contentStream,
$fontKey,
$metrics,
$secretKey,
$config,
);
if ($marker === null) {
$this->logger->info('No steganographic marker recovered from content stream.');
}
return $marker;
}
}
  1. 알려진 페이로드를 알려진 텍스트 런에 인코딩한 다음 동일한 키와 구성으로 다시 디코딩합니다. 복원된 페이로드가 일치하는지 확인합니다.
  2. 의도적으로 잘못된 키로 디코딩하고 결과가 잘못된 페이로드가 아니라 null인지 확인합니다 — 이것이 작동 중인 AEAD 무결성 보증입니다.
  3. 렌더링된 페이지를 검사하고 구성된 편차 비율에서 간격 변화가 시각적으로 드러나지 않는지 확인합니다.
  4. PDF/A 호환성이 필요할 때는 PDF/A 프로파일과 대조해 출력을 검증하고 너비 허용이 위반되지 않는지 확인합니다.
  • 인증 암호화. 페이로드는 AES-256-GCM 또는 ChaCha20-Poly1305로 암호화됩니다. 변조되거나 잘린 캐리어는 복호화 시 인증에 실패합니다. 잘못된 페이로드를 산출하지 않습니다.
  • 암호화별 IV. 모든 암호화마다 새로운 무작위 12바이트 IV가 생성되어, NIST SP 800-38D §5.2.1에 따라 AES-GCM 고유성 요구 사항을 충족합니다.
  • 파생 키. 암호화 키는 시크릿과 폰트 키로부터 HKDF-SHA-256으로 파생됩니다(RFC 5869 §2). 시크릿을 시크릿 매니저에 보관하십시오. 모든 서명 시크릿처럼 취급하십시오.
  • 마커는 문서 콘텐츠입니다. 임베딩된 바이트는 로그 콘텐츠가 아니라 페이지 콘텐츠의 일부입니다. 페이로드나 시크릿 키를 로그에 기록하지 마십시오.

이 페이지는 암호화 임베딩에 관한 것입니다. 모든 규범 출처는 의역되었으며, 어떠한 규범 텍스트도 재현되지 않습니다. ### 견고성 공개

마커는 커닝 조정에 담깁니다. 인쇄 후 재스캔, PDF 변환 도구, 재선형화(re-linearisation), 또는 커닝을 정규화하는 모든 콘텐츠 스트림 재작성에 의해 파괴될 수 있습니다. 이 기법은 생성된 형태로 배포된 문서의 내부 유출 추적에 가장 적합합니다. 적대적 스테가노그래피가 아니며 임의의 다운스트림 처리를 거쳐 생존하지 않습니다. 위협 모델에 고의적 제거가 포함되는 경우 이를 유일한 통제로 의존하지 마십시오.

  • 페이로드가 너무 큼. 페이로드가 텍스트 용량을 초과하면 인코더는 타입이 지정된 오버플로 오류를 발생시킵니다. 페이로드를 줄이거나 캐리어 텍스트를 늘리십시오.
  • 캐리어 텍스트가 너무 적음. 두 문자보다 짧은 텍스트는 캐리어 위치를 제공하지 않으며 오류를 발생시킵니다.
  • 디코딩 시 잘못된 키. 디코딩은 null을 반환합니다. null을 부분 결과가 아니라 “복원된 마커 없음”으로 취급하십시오.
  • 구성 불일치. 인코딩과 디코딩은 동일한 비트 깊이, 편차 비율, 암호, PDF/A 플래그를 사용해야 합니다. 불일치는 복원된 페이로드를 산출하지 않습니다.

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