Skip to content

Commit

Permalink
core: move test data, add docs and link to the specification
Browse files Browse the repository at this point in the history
  • Loading branch information
Denys Smirnov committed Sep 17, 2018
1 parent c08a13c commit c7cfde7
Show file tree
Hide file tree
Showing 9 changed files with 31 additions and 11 deletions.
33 changes: 23 additions & 10 deletions pdf/core/crypt.go
Expand Up @@ -50,6 +50,8 @@ type PdfCrypt struct {
StringFilter string

parser *PdfParser

ivAESZero []byte // a zero buffer used as an initialization vector for AES
}

// AccessPermissions is a list of access permissions for a PDF file.
Expand Down Expand Up @@ -81,11 +83,13 @@ type CryptFilter struct {
Length int
}

// Encryption filters names.
// Table 25, CFM (page 92)
const (
CryptFilterNone = "None"
CryptFilterV2 = "V2"
CryptFilterAESV2 = "AESV2"
CryptFilterAESV3 = "AESV3"
CryptFilterNone = "None" // do not decrypt data
CryptFilterV2 = "V2" // RC4-based filter
CryptFilterAESV2 = "AESV2" // AES-based filter (128 bit key, PDF 1.6)
CryptFilterAESV3 = "AESV3" // AES-based filter (256 bit key, PDF 2.0)
)

// CryptFilters is a map of crypt filter name and underlying CryptFilter info.
Expand Down Expand Up @@ -1113,10 +1117,9 @@ func (crypt *PdfCrypt) Encrypt(obj PdfObject, parentObjNum, parentGenNum int64)
return nil
}

var ivAESZero = make([]byte, aes.BlockSize)

// alg2a retrieves the encryption key from an encrypted document (R >= 5).
// It returns false if the password was wrong.
// 7.6.4.3.2 Algorithm 2.A (page 83)
func (crypt *PdfCrypt) alg2a(pass []byte) (bool, error) {
// O & U: 32 byte hash + 8 byte Validation Salt + 8 byte Key Salt

Expand Down Expand Up @@ -1181,7 +1184,10 @@ func (crypt *PdfCrypt) alg2a(pass []byte) (bool, error) {
if err != nil {
panic(err)
}
iv := ivAESZero
if crypt.ivAESZero == nil {
crypt.ivAESZero = make([]byte, aes.BlockSize)
}
iv := crypt.ivAESZero
cbc := cipher.NewCBCDecrypter(ac, iv)
fkey := make([]byte, 32)
cbc.CryptBlocks(fkey, ekey)
Expand All @@ -1203,22 +1209,27 @@ func (crypt *PdfCrypt) alg2b(data, pwd, userKey []byte) []byte {
return alg2b(data, pwd, userKey)
}

// alg2b_R5 computes a hash for R=5.
// alg2b_R5 computes a hash for R=5, used in a deprecated extension.
// It's used the same way as a hash described in Algorithm 2.B, but it doesn't use the original password
// and the user key to calculate the hash.
func alg2b_R5(data []byte) []byte {
h := sha256.New()
h.Write(data)
return h.Sum(nil)
}

func repeat(buf []byte, sz int) {
bp := sz
// repeat repeats first n bytes of buf until the end of the buffer.
// It assumes that the length of buf is a multiple of n.
func repeat(buf []byte, n int) {
bp := n
for bp < len(buf) {
copy(buf[bp:], buf[:bp])
bp *= 2
}
}

// alg2b computes a hash for R=6.
// 7.6.4.3.3 Algorithm 2.B (page 83)
func alg2b(data, pwd, userKey []byte) []byte {
var (
s256, s384, s512 hash.Hash
Expand Down Expand Up @@ -1582,6 +1593,7 @@ func (crypt *PdfCrypt) alg11(upass []byte) ([]byte, error) {
}

// alg12 authenticates the owner password (R >= 5) and returns the hash.
// 7.6.4.4.10 Algorithm 12 (page 87)
func (crypt *PdfCrypt) alg12(opass []byte) ([]byte, error) {
str := make([]byte, len(opass)+8+48)
i := copy(str, opass)
Expand All @@ -1597,6 +1609,7 @@ func (crypt *PdfCrypt) alg12(opass []byte) ([]byte, error) {
}

// alg13 validates user permissions (P+EncryptMetadata vs Perms) for R=6.
// 7.6.4.4.11 Algorithm 13 (page 87)
func (crypt *PdfCrypt) alg13(fkey []byte) (bool, error) {
perms := crypt.Perms[:16]

Expand Down
2 changes: 1 addition & 1 deletion pdf/core/crypt_file_test.go
Expand Up @@ -16,7 +16,7 @@ import (
pdf "github.com/unidoc/unidoc/pdf/model"
)

const aes3Dir = `../../testfiles/AESv3`
const aes3Dir = `./testdata`

func TestDecryptAES3(t *testing.T) {
cases := []struct {
Expand Down
7 changes: 7 additions & 0 deletions pdf/core/ecb.go
@@ -1,7 +1,14 @@
/*
* This file is subject to the terms and conditions defined in
* file 'LICENSE.md', which is part of this source code package.
*/

package core

import "crypto/cipher"

// ecb implements an Electronic Codebook encryption mode.
// This mode is used to compute or validate document permissions for R=6.
type ecb struct {
b cipher.Block
blockSize int
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.

0 comments on commit c7cfde7

Please sign in to comment.