2016-07-09 14:09:27 +00:00
|
|
|
|
/*
|
|
|
|
|
* This file is subject to the terms and conditions defined in
|
2016-07-29 17:23:39 +00:00
|
|
|
|
* file 'LICENSE.md', which is part of this source code package.
|
2016-07-09 14:09:27 +00:00
|
|
|
|
*/
|
|
|
|
|
|
2016-09-08 17:53:45 +00:00
|
|
|
|
package core
|
2016-07-09 14:09:27 +00:00
|
|
|
|
|
|
|
|
|
import (
|
2018-09-16 00:34:13 +03:00
|
|
|
|
"bytes"
|
2016-07-09 14:09:27 +00:00
|
|
|
|
"crypto/aes"
|
|
|
|
|
"crypto/cipher"
|
|
|
|
|
"crypto/md5"
|
|
|
|
|
"crypto/rand"
|
|
|
|
|
"crypto/rc4"
|
2018-09-16 00:34:13 +03:00
|
|
|
|
"crypto/sha256"
|
|
|
|
|
"crypto/sha512"
|
2018-09-16 02:48:08 +03:00
|
|
|
|
"encoding/binary"
|
2016-07-09 14:09:27 +00:00
|
|
|
|
"errors"
|
|
|
|
|
"fmt"
|
2018-09-16 00:34:13 +03:00
|
|
|
|
"hash"
|
2016-07-09 14:09:27 +00:00
|
|
|
|
"io"
|
2018-09-19 03:33:59 +03:00
|
|
|
|
"math"
|
2018-09-29 04:39:14 +03:00
|
|
|
|
"time"
|
2016-07-17 19:59:17 +00:00
|
|
|
|
|
|
|
|
|
"github.com/unidoc/unidoc/common"
|
2016-07-09 14:09:27 +00:00
|
|
|
|
)
|
|
|
|
|
|
2018-09-29 04:39:14 +03:00
|
|
|
|
type Version struct {
|
|
|
|
|
Major int
|
|
|
|
|
Minor int
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type EncryptInfo struct {
|
|
|
|
|
Version
|
|
|
|
|
Encrypt *PdfObjectDictionary
|
|
|
|
|
ID0, ID1 string
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// PdfCryptNewEncrypt makes the document crypt handler based on a specified crypt filter.
|
|
|
|
|
func PdfCryptNewEncrypt(cf CryptFilter, userPass, ownerPass []byte, perm AccessPermissions) (*PdfCrypt, *EncryptInfo, error) {
|
|
|
|
|
crypter := &PdfCrypt{
|
2018-10-03 05:07:51 +03:00
|
|
|
|
encryptedObjects: make(map[PdfObject]bool),
|
|
|
|
|
cryptFilters: make(cryptFilters),
|
2018-09-29 04:39:14 +03:00
|
|
|
|
encryptStd: stdEncryptDict{
|
|
|
|
|
P: perm,
|
|
|
|
|
EncryptMetadata: true,
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
// TODO(dennwc): define it in the CF interface
|
|
|
|
|
var vers Version
|
|
|
|
|
switch cf.(type) {
|
|
|
|
|
case cryptFilterV2:
|
|
|
|
|
crypter.encrypt.V = 2
|
|
|
|
|
crypter.encryptStd.R = 3
|
|
|
|
|
case cryptFilterAESV2:
|
|
|
|
|
vers.Major, vers.Minor = 1, 5
|
|
|
|
|
crypter.encrypt.V = 4
|
|
|
|
|
crypter.encryptStd.R = 4
|
|
|
|
|
case cryptFilterAESV3:
|
|
|
|
|
vers.Major, vers.Minor = 2, 0
|
|
|
|
|
crypter.encrypt.V = 5
|
|
|
|
|
crypter.encryptStd.R = 6 // TODO(dennwc): a way to set R=5?
|
|
|
|
|
}
|
|
|
|
|
if cf != nil {
|
|
|
|
|
crypter.encrypt.Length = cf.KeyLength() * 8
|
|
|
|
|
}
|
|
|
|
|
const (
|
|
|
|
|
defaultFilter = StandardCryptFilter
|
|
|
|
|
)
|
2018-10-03 05:07:51 +03:00
|
|
|
|
crypter.cryptFilters[defaultFilter] = cf
|
2018-09-29 04:39:14 +03:00
|
|
|
|
if crypter.encrypt.V >= 4 {
|
2018-10-03 05:07:51 +03:00
|
|
|
|
crypter.streamFilter = defaultFilter
|
|
|
|
|
crypter.stringFilter = defaultFilter
|
2018-09-29 04:39:14 +03:00
|
|
|
|
}
|
|
|
|
|
ed := crypter.newEncyptDict()
|
|
|
|
|
|
|
|
|
|
// Prepare the ID object for the trailer.
|
|
|
|
|
hashcode := md5.Sum([]byte(time.Now().Format(time.RFC850)))
|
|
|
|
|
id0 := string(hashcode[:])
|
|
|
|
|
b := make([]byte, 100)
|
|
|
|
|
rand.Read(b)
|
|
|
|
|
hashcode = md5.Sum(b)
|
|
|
|
|
id1 := string(hashcode[:])
|
|
|
|
|
common.Log.Trace("Random b: % x", b)
|
|
|
|
|
|
|
|
|
|
common.Log.Trace("Gen Id 0: % x", id0)
|
|
|
|
|
|
|
|
|
|
// Generate encryption parameters
|
|
|
|
|
if crypter.encryptStd.R < 5 {
|
2018-10-03 05:07:51 +03:00
|
|
|
|
crypter.id0 = string(id0)
|
2018-09-29 04:39:14 +03:00
|
|
|
|
|
|
|
|
|
// Make the O and U objects.
|
|
|
|
|
O, err := crypter.Alg3(userPass, ownerPass)
|
|
|
|
|
if err != nil {
|
|
|
|
|
common.Log.Debug("ERROR: Error generating O for encryption (%s)", err)
|
|
|
|
|
return nil, nil, err
|
|
|
|
|
}
|
|
|
|
|
crypter.encryptStd.O = []byte(O)
|
|
|
|
|
common.Log.Trace("gen O: % x", O)
|
|
|
|
|
U, key, err := crypter.Alg5(userPass)
|
|
|
|
|
if err != nil {
|
|
|
|
|
common.Log.Debug("ERROR: Error generating O for encryption (%s)", err)
|
|
|
|
|
return nil, nil, err
|
|
|
|
|
}
|
|
|
|
|
common.Log.Trace("gen U: % x", U)
|
|
|
|
|
crypter.encryptStd.U = []byte(U)
|
2018-10-03 05:07:51 +03:00
|
|
|
|
crypter.encryptionKey = key
|
2018-09-29 04:39:14 +03:00
|
|
|
|
|
|
|
|
|
ed.Set("O", MakeHexString(O))
|
|
|
|
|
ed.Set("U", MakeHexString(U))
|
|
|
|
|
} else { // R >= 5
|
|
|
|
|
err := crypter.GenerateParams(userPass, ownerPass)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, nil, err
|
|
|
|
|
}
|
|
|
|
|
ed.Set("O", MakeString(string(crypter.encryptStd.O)))
|
|
|
|
|
ed.Set("U", MakeString(string(crypter.encryptStd.U)))
|
|
|
|
|
ed.Set("OE", MakeString(string(crypter.encryptStd.OE)))
|
|
|
|
|
ed.Set("UE", MakeString(string(crypter.encryptStd.UE)))
|
|
|
|
|
ed.Set("EncryptMetadata", MakeBool(crypter.encryptStd.EncryptMetadata))
|
|
|
|
|
if crypter.encryptStd.R > 5 {
|
|
|
|
|
ed.Set("Perms", MakeString(string(crypter.encryptStd.Perms)))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if crypter.encrypt.V >= 4 {
|
|
|
|
|
if err := crypter.saveCryptFilters(ed); err != nil {
|
|
|
|
|
return nil, nil, err
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return crypter, &EncryptInfo{
|
|
|
|
|
Version: vers,
|
|
|
|
|
Encrypt: ed,
|
|
|
|
|
ID0: id0, ID1: id1,
|
|
|
|
|
}, nil
|
|
|
|
|
}
|
|
|
|
|
|
2017-08-03 15:13:40 +00:00
|
|
|
|
// PdfCrypt provides PDF encryption/decryption support.
|
|
|
|
|
// The PDF standard supports encryption of strings and streams (Section 7.6).
|
|
|
|
|
// TODO (v3): Consider unexporting.
|
2016-07-09 14:09:27 +00:00
|
|
|
|
type PdfCrypt struct {
|
2018-09-29 04:39:14 +03:00
|
|
|
|
encrypt encryptDict
|
|
|
|
|
encryptStd stdEncryptDict
|
|
|
|
|
|
2018-10-03 05:07:51 +03:00
|
|
|
|
id0 string
|
|
|
|
|
encryptionKey []byte
|
|
|
|
|
decryptedObjects map[PdfObject]bool
|
|
|
|
|
encryptedObjects map[PdfObject]bool
|
|
|
|
|
authenticated bool
|
2016-07-09 14:09:27 +00:00
|
|
|
|
// Crypt filters (V4).
|
2018-10-03 05:07:51 +03:00
|
|
|
|
cryptFilters cryptFilters
|
|
|
|
|
streamFilter string
|
|
|
|
|
stringFilter string
|
2017-03-29 15:54:50 +00:00
|
|
|
|
|
|
|
|
|
parser *PdfParser
|
2018-09-17 17:36:31 +03:00
|
|
|
|
|
2018-09-26 04:54:00 +03:00
|
|
|
|
decryptedObjNum map[int]struct{}
|
|
|
|
|
ivAESZero []byte // a zero buffer used as an initialization vector for AES
|
2016-07-09 14:09:27 +00:00
|
|
|
|
}
|
|
|
|
|
|
2018-09-29 04:39:14 +03:00
|
|
|
|
func (crypt *PdfCrypt) newEncyptDict() *PdfObjectDictionary {
|
|
|
|
|
// Generate the encryption dictionary.
|
|
|
|
|
ed := MakeDict()
|
|
|
|
|
ed.Set("Filter", MakeName("Standard"))
|
|
|
|
|
ed.Set("V", MakeInteger(int64(crypt.encrypt.V)))
|
|
|
|
|
ed.Set("Length", MakeInteger(int64(crypt.encrypt.Length)))
|
|
|
|
|
ed.Set("P", MakeInteger(int64(crypt.encryptStd.P)))
|
|
|
|
|
ed.Set("R", MakeInteger(int64(crypt.encryptStd.R)))
|
|
|
|
|
return ed
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// String returns a descriptive information string about the encryption method used.
|
|
|
|
|
func (crypt *PdfCrypt) String() string {
|
|
|
|
|
if crypt == nil {
|
|
|
|
|
return ""
|
|
|
|
|
}
|
|
|
|
|
// TODO(dennwc): define a String method on CF
|
|
|
|
|
str := crypt.encrypt.Filter + " - "
|
|
|
|
|
|
|
|
|
|
if crypt.encrypt.V == 0 {
|
|
|
|
|
str += "Undocumented algorithm"
|
|
|
|
|
} else if crypt.encrypt.V == 1 {
|
|
|
|
|
// RC4 or AES (bits: 40)
|
|
|
|
|
str += "RC4: 40 bits"
|
|
|
|
|
} else if crypt.encrypt.V == 2 {
|
|
|
|
|
str += fmt.Sprintf("RC4: %d bits", crypt.encrypt.Length)
|
|
|
|
|
} else if crypt.encrypt.V == 3 {
|
|
|
|
|
str += "Unpublished algorithm"
|
|
|
|
|
} else if crypt.encrypt.V >= 4 {
|
|
|
|
|
// Look at CF, StmF, StrF
|
2018-10-03 05:07:51 +03:00
|
|
|
|
str += fmt.Sprintf("Stream filter: %s - String filter: %s", crypt.streamFilter, crypt.stringFilter)
|
2018-09-29 04:39:14 +03:00
|
|
|
|
str += "; Crypt filters:"
|
2018-10-03 05:07:51 +03:00
|
|
|
|
for name, cf := range crypt.cryptFilters {
|
2018-09-29 04:39:14 +03:00
|
|
|
|
str += fmt.Sprintf(" - %s: %s (%d)", name, cf.Name(), cf.KeyLength())
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
perms := crypt.GetAccessPermissions()
|
|
|
|
|
str += fmt.Sprintf(" - %#v", perms)
|
|
|
|
|
|
|
|
|
|
return str
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type authEvent string
|
|
|
|
|
|
|
|
|
|
const (
|
|
|
|
|
authEventDocOpen = authEvent("DocOpen")
|
|
|
|
|
authEventEFOpen = authEvent("EFOpen")
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
type cryptFiltersDict map[string]cryptFilterDict
|
|
|
|
|
|
|
|
|
|
// encryptDict is a set of field common to all encryption dictionaries.
|
|
|
|
|
type encryptDict struct {
|
|
|
|
|
Filter string // (Required) The name of the preferred security handler for this document.
|
|
|
|
|
V int // (Required) A code specifying the algorithm to be used in encrypting and decrypting the document.
|
|
|
|
|
SubFilter string // Completely specifies the format and interpretation of the encryption dictionary.
|
|
|
|
|
Length int // The length of the encryption key, in bits.
|
|
|
|
|
CF cryptFiltersDict // Crypt filters dictionary.
|
|
|
|
|
StmF string // The filter that shall be used by default when decrypting streams.
|
|
|
|
|
StrF string // The filter that shall be used when decrypting all strings in the document.
|
|
|
|
|
EFF string // The filter that shall be used when decrypting embedded file streams.
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// stdEncryptDict is a set of additional fields used in standard encryption dictionary.
|
|
|
|
|
type stdEncryptDict struct {
|
|
|
|
|
R int // (Required) A number specifying which revision of the standard security handler shall be used.
|
|
|
|
|
O, U []byte
|
|
|
|
|
OE, UE []byte // R=6
|
|
|
|
|
|
|
|
|
|
P AccessPermissions
|
|
|
|
|
Perms []byte // An encrypted copy of P (16 bytes). Used to verify permissions. R=6
|
|
|
|
|
EncryptMetadata bool // Indicates whether the document-level metadata stream shall be encrypted.
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-29 00:43:24 +03:00
|
|
|
|
// AccessPermissions is a bitmask of access permissions for a PDF file.
|
|
|
|
|
type AccessPermissions uint32
|
2017-07-12 09:48:16 +00:00
|
|
|
|
|
2018-09-29 00:43:24 +03:00
|
|
|
|
const (
|
|
|
|
|
// PermOwner grants all permissions.
|
|
|
|
|
PermOwner = AccessPermissions(math.MaxUint32)
|
|
|
|
|
|
|
|
|
|
PermPrinting = AccessPermissions(1 << 2) // bit 3
|
|
|
|
|
PermModify = AccessPermissions(1 << 3) // bit 4
|
|
|
|
|
PermExtractGraphics = AccessPermissions(1 << 4) // bit 5
|
|
|
|
|
PermAnnotate = AccessPermissions(1 << 5) // bit 6
|
|
|
|
|
// PermFillForms allow form filling, if annotation is disabled? If annotation enabled, is not looked at.
|
|
|
|
|
PermFillForms = AccessPermissions(1 << 8) // bit 9
|
|
|
|
|
PermDisabilityExtract = AccessPermissions(1 << 9) // bit 10 // TODO: not clear what this means!
|
|
|
|
|
// PermRotateInsert allows rotating, editing page order.
|
|
|
|
|
PermRotateInsert = AccessPermissions(1 << 10) // bit 11
|
|
|
|
|
// PermFullPrintQuality limits print quality (lowres), assuming Printing bit is set.
|
|
|
|
|
PermFullPrintQuality = AccessPermissions(1 << 11) // bit 12
|
|
|
|
|
)
|
2017-07-12 09:48:16 +00:00
|
|
|
|
|
2018-09-29 00:43:24 +03:00
|
|
|
|
// Allowed checks if a set of permissions can be granted.
|
|
|
|
|
func (p AccessPermissions) Allowed(p2 AccessPermissions) bool {
|
|
|
|
|
return p&p2 == p2
|
2016-07-09 16:40:39 +00:00
|
|
|
|
}
|
|
|
|
|
|
2016-07-09 14:09:27 +00:00
|
|
|
|
const padding = "\x28\xBF\x4E\x5E\x4E\x75\x8A\x41\x64\x00\x4E\x56\xFF" +
|
|
|
|
|
"\xFA\x01\x08\x2E\x2E\x00\xB6\xD0\x68\x3E\x80\x2F\x0C" +
|
|
|
|
|
"\xA9\xFE\x64\x53\x69\x7A"
|
|
|
|
|
|
2018-09-19 23:48:50 +03:00
|
|
|
|
// StandardCryptFilter is a default name for a standard crypt filter.
|
|
|
|
|
const StandardCryptFilter = "StdCF"
|
|
|
|
|
|
2018-10-03 05:07:51 +03:00
|
|
|
|
func newCryptFiltersV2(length int) cryptFilters {
|
|
|
|
|
return cryptFilters{
|
2018-09-25 02:58:49 +03:00
|
|
|
|
StandardCryptFilter: NewCryptFilterV2(length),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-26 02:16:17 +03:00
|
|
|
|
// NewCryptFilterV2 creates a RC4-based filter with a specified key length (in bytes).
|
2018-09-25 02:58:49 +03:00
|
|
|
|
func NewCryptFilterV2(length int) CryptFilter {
|
2018-09-29 04:39:14 +03:00
|
|
|
|
f, err := newCryptFilterV2(cryptFilterDict{Length: length})
|
|
|
|
|
if err != nil {
|
|
|
|
|
panic(err)
|
2018-09-25 02:58:49 +03:00
|
|
|
|
}
|
2018-09-29 04:39:14 +03:00
|
|
|
|
return f
|
2018-09-25 02:58:49 +03:00
|
|
|
|
}
|
|
|
|
|
|
2018-09-26 02:16:17 +03:00
|
|
|
|
// NewCryptFilterAESV2 creates an AES-based filter with a 128 bit key (AESV2).
|
2018-09-25 02:58:49 +03:00
|
|
|
|
func NewCryptFilterAESV2() CryptFilter {
|
2018-09-29 04:39:14 +03:00
|
|
|
|
f, err := newCryptFilterAESV2(cryptFilterDict{})
|
|
|
|
|
if err != nil {
|
|
|
|
|
panic(err)
|
2018-09-25 02:58:49 +03:00
|
|
|
|
}
|
2018-09-29 04:39:14 +03:00
|
|
|
|
return f
|
2018-09-25 02:58:49 +03:00
|
|
|
|
}
|
|
|
|
|
|
2018-09-26 02:16:17 +03:00
|
|
|
|
// NewCryptFilterAESV3 creates an AES-based filter with a 256 bit key (AESV3).
|
2018-09-25 02:58:49 +03:00
|
|
|
|
func NewCryptFilterAESV3() CryptFilter {
|
2018-09-29 04:39:14 +03:00
|
|
|
|
f, err := newCryptFilterAESV3(cryptFilterDict{})
|
|
|
|
|
if err != nil {
|
|
|
|
|
panic(err)
|
2018-09-25 02:58:49 +03:00
|
|
|
|
}
|
2018-09-29 04:39:14 +03:00
|
|
|
|
return f
|
2016-07-09 14:09:27 +00:00
|
|
|
|
}
|
|
|
|
|
|
2018-10-03 05:07:51 +03:00
|
|
|
|
// cryptFilters is a map of crypt filter name and underlying CryptFilter info.
|
|
|
|
|
type cryptFilters map[string]CryptFilter
|
2016-07-09 14:09:27 +00:00
|
|
|
|
|
2018-09-19 06:02:15 +03:00
|
|
|
|
// LoadCryptFilters loads crypt filter information from the encryption dictionary (V>=4).
|
2017-08-03 15:13:40 +00:00
|
|
|
|
// TODO (v3): Unexport.
|
|
|
|
|
func (crypt *PdfCrypt) LoadCryptFilters(ed *PdfObjectDictionary) error {
|
2018-10-03 05:07:51 +03:00
|
|
|
|
crypt.cryptFilters = cryptFilters{}
|
2016-07-09 14:09:27 +00:00
|
|
|
|
|
2017-07-08 21:04:13 +00:00
|
|
|
|
obj := ed.Get("CF")
|
2017-03-29 15:54:50 +00:00
|
|
|
|
obj = TraceToDirectObject(obj) // XXX may need to resolve reference...
|
|
|
|
|
if ref, isRef := obj.(*PdfObjectReference); isRef {
|
2017-08-03 15:13:40 +00:00
|
|
|
|
o, err := crypt.parser.LookupByReference(*ref)
|
2017-03-29 15:54:50 +00:00
|
|
|
|
if err != nil {
|
|
|
|
|
common.Log.Debug("Error looking up CF reference")
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
obj = TraceToDirectObject(o)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cf, ok := obj.(*PdfObjectDictionary)
|
2016-07-09 14:09:27 +00:00
|
|
|
|
if !ok {
|
2017-03-29 15:54:50 +00:00
|
|
|
|
common.Log.Debug("Invalid CF, type: %T", obj)
|
2016-07-09 14:09:27 +00:00
|
|
|
|
return errors.New("Invalid CF")
|
|
|
|
|
}
|
|
|
|
|
|
2017-07-08 21:04:13 +00:00
|
|
|
|
for _, name := range cf.Keys() {
|
|
|
|
|
v := cf.Get(name)
|
|
|
|
|
|
2017-03-29 15:54:50 +00:00
|
|
|
|
if ref, isRef := v.(*PdfObjectReference); isRef {
|
2017-08-03 15:13:40 +00:00
|
|
|
|
o, err := crypt.parser.LookupByReference(*ref)
|
2017-03-29 15:54:50 +00:00
|
|
|
|
if err != nil {
|
|
|
|
|
common.Log.Debug("Error lookup up dictionary reference")
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
v = TraceToDirectObject(o)
|
|
|
|
|
}
|
|
|
|
|
|
2016-07-09 14:09:27 +00:00
|
|
|
|
dict, ok := v.(*PdfObjectDictionary)
|
|
|
|
|
if !ok {
|
2017-03-29 15:54:50 +00:00
|
|
|
|
return fmt.Errorf("Invalid dict in CF (name %s) - not a dictionary but %T", name, v)
|
2016-07-09 14:09:27 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if name == "Identity" {
|
2016-10-31 21:48:25 +00:00
|
|
|
|
common.Log.Debug("ERROR - Cannot overwrite the identity filter - Trying next")
|
2016-07-09 14:09:27 +00:00
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-29 04:39:14 +03:00
|
|
|
|
var cfd cryptFilterDict
|
|
|
|
|
if err := cfd.ReadFrom(dict); err != nil {
|
|
|
|
|
return err
|
2016-07-09 14:09:27 +00:00
|
|
|
|
}
|
2018-09-29 04:39:14 +03:00
|
|
|
|
fnc, err := getCryptFilterMethod(cfd.CFM)
|
2018-09-25 02:58:49 +03:00
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
2016-07-09 14:09:27 +00:00
|
|
|
|
}
|
2018-09-29 04:39:14 +03:00
|
|
|
|
cf, err := fnc(cfd)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
2016-07-09 14:09:27 +00:00
|
|
|
|
}
|
2018-10-03 05:07:51 +03:00
|
|
|
|
crypt.cryptFilters[string(name)] = cf
|
2016-07-09 14:09:27 +00:00
|
|
|
|
}
|
|
|
|
|
// Cannot be overwritten.
|
2018-10-03 05:07:51 +03:00
|
|
|
|
crypt.cryptFilters["Identity"] = cryptFilteridentity{}
|
2016-07-09 14:09:27 +00:00
|
|
|
|
|
|
|
|
|
// StrF strings filter.
|
2018-10-03 05:07:51 +03:00
|
|
|
|
crypt.stringFilter = "Identity"
|
2017-07-08 21:04:13 +00:00
|
|
|
|
if strf, ok := ed.Get("StrF").(*PdfObjectName); ok {
|
2018-10-03 05:07:51 +03:00
|
|
|
|
if _, exists := crypt.cryptFilters[string(*strf)]; !exists {
|
2016-07-09 14:09:27 +00:00
|
|
|
|
return fmt.Errorf("Crypt filter for StrF not specified in CF dictionary (%s)", *strf)
|
|
|
|
|
}
|
2018-10-03 05:07:51 +03:00
|
|
|
|
crypt.stringFilter = string(*strf)
|
2016-07-09 14:09:27 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// StmF streams filter.
|
2018-10-03 05:07:51 +03:00
|
|
|
|
crypt.streamFilter = "Identity"
|
2017-07-08 21:04:13 +00:00
|
|
|
|
if stmf, ok := ed.Get("StmF").(*PdfObjectName); ok {
|
2018-10-03 05:07:51 +03:00
|
|
|
|
if _, exists := crypt.cryptFilters[string(*stmf)]; !exists {
|
2016-07-09 14:09:27 +00:00
|
|
|
|
return fmt.Errorf("Crypt filter for StmF not specified in CF dictionary (%s)", *stmf)
|
|
|
|
|
}
|
2018-10-03 05:07:51 +03:00
|
|
|
|
crypt.streamFilter = string(*stmf)
|
2016-07-09 14:09:27 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-29 04:39:14 +03:00
|
|
|
|
// saveCryptFilters saves crypt filter information to the encryption dictionary (V>=4).
|
2018-09-19 06:02:15 +03:00
|
|
|
|
// TODO (v3): Unexport.
|
2018-09-29 04:39:14 +03:00
|
|
|
|
func (crypt *PdfCrypt) saveCryptFilters(ed *PdfObjectDictionary) error {
|
|
|
|
|
if crypt.encrypt.V < 4 {
|
2018-09-19 06:02:15 +03:00
|
|
|
|
return errors.New("can only be used with V>=4")
|
|
|
|
|
}
|
|
|
|
|
cf := MakeDict()
|
|
|
|
|
ed.Set("CF", cf)
|
|
|
|
|
|
2018-10-03 05:07:51 +03:00
|
|
|
|
for name, filter := range crypt.cryptFilters {
|
2018-09-19 06:02:15 +03:00
|
|
|
|
if name == "Identity" {
|
|
|
|
|
continue
|
|
|
|
|
}
|
2018-09-29 04:39:14 +03:00
|
|
|
|
v := cryptFilterToDict(filter, "")
|
2018-09-19 06:02:15 +03:00
|
|
|
|
cf.Set(PdfObjectName(name), v)
|
|
|
|
|
}
|
2018-10-03 05:07:51 +03:00
|
|
|
|
ed.Set("StrF", MakeName(crypt.stringFilter))
|
|
|
|
|
ed.Set("StmF", MakeName(crypt.streamFilter))
|
2018-09-19 06:02:15 +03:00
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-29 04:39:14 +03:00
|
|
|
|
// PdfCryptNewDecrypt makes the document crypt handler based on the encryption dictionary
|
2017-08-03 15:13:40 +00:00
|
|
|
|
// and trailer dictionary. Returns an error on failure to process.
|
2018-09-29 04:39:14 +03:00
|
|
|
|
func PdfCryptNewDecrypt(parser *PdfParser, ed, trailer *PdfObjectDictionary) (*PdfCrypt, error) {
|
|
|
|
|
crypter := &PdfCrypt{
|
2018-10-03 05:07:51 +03:00
|
|
|
|
authenticated: false,
|
|
|
|
|
decryptedObjects: make(map[PdfObject]bool),
|
|
|
|
|
encryptedObjects: make(map[PdfObject]bool),
|
2018-09-26 04:54:00 +03:00
|
|
|
|
decryptedObjNum: make(map[int]struct{}),
|
|
|
|
|
parser: parser,
|
|
|
|
|
}
|
2016-07-09 14:09:27 +00:00
|
|
|
|
|
2017-07-08 21:04:13 +00:00
|
|
|
|
filter, ok := ed.Get("Filter").(*PdfObjectName)
|
2016-07-09 14:09:27 +00:00
|
|
|
|
if !ok {
|
2016-10-31 21:48:25 +00:00
|
|
|
|
common.Log.Debug("ERROR Crypt dictionary missing required Filter field!")
|
2016-07-09 14:09:27 +00:00
|
|
|
|
return crypter, errors.New("Required crypt field Filter missing")
|
|
|
|
|
}
|
|
|
|
|
if *filter != "Standard" {
|
2016-10-31 21:48:25 +00:00
|
|
|
|
common.Log.Debug("ERROR Unsupported filter (%s)", *filter)
|
2016-07-09 14:09:27 +00:00
|
|
|
|
return crypter, errors.New("Unsupported Filter")
|
|
|
|
|
}
|
2018-09-29 04:39:14 +03:00
|
|
|
|
crypter.encrypt.Filter = string(*filter)
|
2016-07-09 14:09:27 +00:00
|
|
|
|
|
2018-09-29 04:39:14 +03:00
|
|
|
|
if subfilter, ok := ed.Get("SubFilter").(*PdfObjectString); ok {
|
|
|
|
|
crypter.encrypt.SubFilter = subfilter.Str()
|
2016-07-17 19:59:17 +00:00
|
|
|
|
common.Log.Debug("Using subfilter %s", subfilter)
|
2016-07-09 14:09:27 +00:00
|
|
|
|
}
|
|
|
|
|
|
2017-07-08 21:04:13 +00:00
|
|
|
|
if L, ok := ed.Get("Length").(*PdfObjectInteger); ok {
|
2016-07-09 14:09:27 +00:00
|
|
|
|
if (*L % 8) != 0 {
|
2016-10-31 21:48:25 +00:00
|
|
|
|
common.Log.Debug("ERROR Invalid encryption length")
|
2016-07-09 14:09:27 +00:00
|
|
|
|
return crypter, errors.New("Invalid encryption length")
|
|
|
|
|
}
|
2018-09-29 04:39:14 +03:00
|
|
|
|
crypter.encrypt.Length = int(*L)
|
2016-07-09 14:09:27 +00:00
|
|
|
|
} else {
|
2018-09-29 04:39:14 +03:00
|
|
|
|
crypter.encrypt.Length = 40
|
2016-07-09 14:09:27 +00:00
|
|
|
|
}
|
|
|
|
|
|
2018-09-29 04:39:14 +03:00
|
|
|
|
crypter.encrypt.V = 0
|
2018-09-25 01:39:00 +03:00
|
|
|
|
if v, ok := ed.Get("V").(*PdfObjectInteger); ok {
|
|
|
|
|
V := int(*v)
|
2018-09-29 04:39:14 +03:00
|
|
|
|
crypter.encrypt.V = V
|
2018-09-25 01:39:00 +03:00
|
|
|
|
if V >= 1 && V <= 2 {
|
2016-07-09 14:09:27 +00:00
|
|
|
|
// Default algorithm is V2.
|
2018-10-03 05:07:51 +03:00
|
|
|
|
crypter.cryptFilters = newCryptFiltersV2(crypter.encrypt.Length)
|
2018-09-25 01:39:00 +03:00
|
|
|
|
} else if V >= 4 && V <= 5 {
|
2016-07-09 14:09:27 +00:00
|
|
|
|
if err := crypter.LoadCryptFilters(ed); err != nil {
|
|
|
|
|
return crypter, err
|
|
|
|
|
}
|
|
|
|
|
} else {
|
2018-09-25 01:39:00 +03:00
|
|
|
|
common.Log.Debug("ERROR Unsupported encryption algo V = %d", V)
|
2016-07-09 14:09:27 +00:00
|
|
|
|
return crypter, errors.New("Unsupported algorithm")
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-07-08 21:04:13 +00:00
|
|
|
|
R, ok := ed.Get("R").(*PdfObjectInteger)
|
2016-07-09 14:09:27 +00:00
|
|
|
|
if !ok {
|
|
|
|
|
return crypter, errors.New("Encrypt dictionary missing R")
|
|
|
|
|
}
|
2018-09-19 06:02:15 +03:00
|
|
|
|
// TODO(dennwc): according to spec, R should be validated according to V value
|
2018-09-16 00:34:13 +03:00
|
|
|
|
if *R < 2 || *R > 6 {
|
|
|
|
|
return crypter, fmt.Errorf("Invalid R (%d)", *R)
|
2016-07-09 14:09:27 +00:00
|
|
|
|
}
|
2018-09-29 04:39:14 +03:00
|
|
|
|
crypter.encryptStd.R = int(*R)
|
2016-07-09 14:09:27 +00:00
|
|
|
|
|
2017-07-08 21:04:13 +00:00
|
|
|
|
O, ok := ed.Get("O").(*PdfObjectString)
|
2016-07-09 14:09:27 +00:00
|
|
|
|
if !ok {
|
|
|
|
|
return crypter, errors.New("Encrypt dictionary missing O")
|
|
|
|
|
}
|
2018-09-29 04:39:14 +03:00
|
|
|
|
if crypter.encryptStd.R == 5 || crypter.encryptStd.R == 6 {
|
2018-09-16 04:13:24 +03:00
|
|
|
|
// the spec says =48 bytes, but Acrobat pads them out longer
|
2018-09-26 01:08:19 +03:00
|
|
|
|
if len(O.Str()) < 48 {
|
|
|
|
|
return crypter, fmt.Errorf("Length(O) < 48 (%d)", len(O.Str()))
|
2018-09-16 00:34:13 +03:00
|
|
|
|
}
|
2018-09-26 01:08:19 +03:00
|
|
|
|
} else if len(O.Str()) != 32 {
|
2018-07-14 02:25:29 +00:00
|
|
|
|
return crypter, fmt.Errorf("Length(O) != 32 (%d)", len(O.Str()))
|
2016-07-09 14:09:27 +00:00
|
|
|
|
}
|
2018-09-29 04:39:14 +03:00
|
|
|
|
crypter.encryptStd.O = O.Bytes()
|
2016-07-09 14:09:27 +00:00
|
|
|
|
|
2017-07-08 21:04:13 +00:00
|
|
|
|
U, ok := ed.Get("U").(*PdfObjectString)
|
2016-07-09 14:09:27 +00:00
|
|
|
|
if !ok {
|
|
|
|
|
return crypter, errors.New("Encrypt dictionary missing U")
|
|
|
|
|
}
|
2018-09-29 04:39:14 +03:00
|
|
|
|
if crypter.encryptStd.R == 5 || crypter.encryptStd.R == 6 {
|
2018-09-16 04:13:24 +03:00
|
|
|
|
// the spec says =48 bytes, but Acrobat pads them out longer
|
2018-09-26 01:08:19 +03:00
|
|
|
|
if len(U.Str()) < 48 {
|
|
|
|
|
return crypter, fmt.Errorf("Length(U) < 48 (%d)", len(U.Str()))
|
2018-09-16 00:34:13 +03:00
|
|
|
|
}
|
2018-09-26 01:08:19 +03:00
|
|
|
|
} else if len(U.Str()) != 32 {
|
2016-11-08 22:27:39 +00:00
|
|
|
|
// Strictly this does not cause an error.
|
|
|
|
|
// If O is OK and others then can still read the file.
|
2018-07-14 02:25:29 +00:00
|
|
|
|
common.Log.Debug("Warning: Length(U) != 32 (%d)", len(U.Str()))
|
2016-11-08 22:27:39 +00:00
|
|
|
|
//return crypter, errors.New("Length(U) != 32")
|
2016-07-09 14:09:27 +00:00
|
|
|
|
}
|
2018-09-29 04:39:14 +03:00
|
|
|
|
crypter.encryptStd.U = U.Bytes()
|
2016-07-09 14:09:27 +00:00
|
|
|
|
|
2018-09-29 04:39:14 +03:00
|
|
|
|
if crypter.encryptStd.R >= 5 {
|
2018-09-16 00:34:13 +03:00
|
|
|
|
OE, ok := ed.Get("OE").(*PdfObjectString)
|
|
|
|
|
if !ok {
|
|
|
|
|
return crypter, errors.New("Encrypt dictionary missing OE")
|
|
|
|
|
}
|
2018-09-26 01:21:07 +03:00
|
|
|
|
if len(OE.Str()) != 32 {
|
|
|
|
|
return crypter, fmt.Errorf("Length(OE) != 32 (%d)", len(OE.Str()))
|
2018-09-16 00:34:13 +03:00
|
|
|
|
}
|
2018-09-29 04:39:14 +03:00
|
|
|
|
crypter.encryptStd.OE = OE.Bytes()
|
2018-09-16 00:34:13 +03:00
|
|
|
|
|
|
|
|
|
UE, ok := ed.Get("UE").(*PdfObjectString)
|
|
|
|
|
if !ok {
|
|
|
|
|
return crypter, errors.New("Encrypt dictionary missing UE")
|
|
|
|
|
}
|
2018-09-26 01:21:07 +03:00
|
|
|
|
if len(UE.Str()) != 32 {
|
|
|
|
|
return crypter, fmt.Errorf("Length(UE) != 32 (%d)", len(UE.Str()))
|
2018-09-16 00:34:13 +03:00
|
|
|
|
}
|
2018-09-29 04:39:14 +03:00
|
|
|
|
crypter.encryptStd.UE = UE.Bytes()
|
2018-09-16 00:34:13 +03:00
|
|
|
|
}
|
|
|
|
|
|
2017-07-08 21:04:13 +00:00
|
|
|
|
P, ok := ed.Get("P").(*PdfObjectInteger)
|
2016-07-09 14:09:27 +00:00
|
|
|
|
if !ok {
|
|
|
|
|
return crypter, errors.New("Encrypt dictionary missing permissions attr")
|
|
|
|
|
}
|
2018-09-29 04:39:14 +03:00
|
|
|
|
crypter.encryptStd.P = AccessPermissions(*P)
|
2016-07-09 14:09:27 +00:00
|
|
|
|
|
2018-09-29 04:39:14 +03:00
|
|
|
|
if crypter.encryptStd.R == 6 {
|
2018-09-16 00:34:13 +03:00
|
|
|
|
Perms, ok := ed.Get("Perms").(*PdfObjectString)
|
|
|
|
|
if !ok {
|
|
|
|
|
return crypter, errors.New("Encrypt dictionary missing Perms")
|
|
|
|
|
}
|
2018-09-26 01:21:07 +03:00
|
|
|
|
if len(Perms.Str()) != 16 {
|
|
|
|
|
return crypter, fmt.Errorf("Length(Perms) != 16 (%d)", len(Perms.Str()))
|
2018-09-16 00:34:13 +03:00
|
|
|
|
}
|
2018-09-29 04:39:14 +03:00
|
|
|
|
crypter.encryptStd.Perms = Perms.Bytes()
|
2018-09-16 00:34:13 +03:00
|
|
|
|
}
|
|
|
|
|
|
2017-07-08 21:04:13 +00:00
|
|
|
|
em, ok := ed.Get("EncryptMetadata").(*PdfObjectBool)
|
2016-07-09 14:09:27 +00:00
|
|
|
|
if ok {
|
2018-09-29 04:39:14 +03:00
|
|
|
|
crypter.encryptStd.EncryptMetadata = bool(*em)
|
2016-07-09 14:09:27 +00:00
|
|
|
|
} else {
|
2018-09-29 04:39:14 +03:00
|
|
|
|
crypter.encryptStd.EncryptMetadata = true // True by default.
|
2016-07-09 14:09:27 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Default: empty ID.
|
|
|
|
|
// Strictly, if file is encrypted, the ID should always be specified
|
|
|
|
|
// but clearly not everyone is following the specification.
|
2018-07-14 02:25:29 +00:00
|
|
|
|
id0 := ""
|
2018-07-15 17:52:53 +00:00
|
|
|
|
if idArray, ok := trailer.Get("ID").(*PdfObjectArray); ok && idArray.Len() >= 1 {
|
|
|
|
|
id0obj, ok := GetString(idArray.Get(0))
|
2016-07-09 14:09:27 +00:00
|
|
|
|
if !ok {
|
|
|
|
|
return crypter, errors.New("Invalid trailer ID")
|
|
|
|
|
}
|
2018-07-14 02:25:29 +00:00
|
|
|
|
id0 = id0obj.Str()
|
2017-03-29 15:54:50 +00:00
|
|
|
|
} else {
|
|
|
|
|
common.Log.Debug("Trailer ID array missing or invalid!")
|
2016-07-09 14:09:27 +00:00
|
|
|
|
}
|
2018-10-03 05:07:51 +03:00
|
|
|
|
crypter.id0 = id0
|
2016-07-09 14:09:27 +00:00
|
|
|
|
|
|
|
|
|
return crypter, nil
|
|
|
|
|
}
|
|
|
|
|
|
2017-08-03 15:13:40 +00:00
|
|
|
|
// GetAccessPermissions returns the PDF access permissions as an AccessPermissions object.
|
|
|
|
|
func (crypt *PdfCrypt) GetAccessPermissions() AccessPermissions {
|
2018-09-29 04:39:14 +03:00
|
|
|
|
return crypt.encryptStd.P
|
2016-07-09 16:40:39 +00:00
|
|
|
|
}
|
|
|
|
|
|
2017-08-03 15:13:40 +00:00
|
|
|
|
// Check whether the specified password can be used to decrypt the document.
|
|
|
|
|
func (crypt *PdfCrypt) authenticate(password []byte) (bool, error) {
|
2016-07-09 14:09:27 +00:00
|
|
|
|
// Also build the encryption/decryption key.
|
|
|
|
|
|
2018-10-03 05:07:51 +03:00
|
|
|
|
crypt.authenticated = false
|
2018-09-29 04:39:14 +03:00
|
|
|
|
if crypt.encryptStd.R >= 5 {
|
2018-09-16 02:48:08 +03:00
|
|
|
|
authenticated, err := crypt.alg2a(password)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return false, err
|
|
|
|
|
}
|
2018-10-03 05:07:51 +03:00
|
|
|
|
crypt.authenticated = authenticated
|
2018-09-16 02:48:08 +03:00
|
|
|
|
return authenticated, err
|
|
|
|
|
}
|
2016-07-09 14:09:27 +00:00
|
|
|
|
|
|
|
|
|
// Try user password.
|
2017-03-02 18:06:32 +00:00
|
|
|
|
common.Log.Trace("Debugging authentication - user pass")
|
2018-07-14 02:25:29 +00:00
|
|
|
|
authenticated, err := crypt.alg6(password)
|
2016-07-09 14:09:27 +00:00
|
|
|
|
if err != nil {
|
|
|
|
|
return false, err
|
|
|
|
|
}
|
|
|
|
|
if authenticated {
|
2018-10-03 05:07:51 +03:00
|
|
|
|
common.Log.Trace("this.authenticated = True")
|
|
|
|
|
crypt.authenticated = true
|
2016-07-09 14:09:27 +00:00
|
|
|
|
return true, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Try owner password also.
|
|
|
|
|
// May not be necessary if only want to get all contents.
|
|
|
|
|
// (user pass needs to be known or empty).
|
2017-03-02 18:06:32 +00:00
|
|
|
|
common.Log.Trace("Debugging authentication - owner pass")
|
2018-07-14 02:25:29 +00:00
|
|
|
|
authenticated, err = crypt.alg7(password)
|
2016-07-09 14:09:27 +00:00
|
|
|
|
if err != nil {
|
|
|
|
|
return false, err
|
|
|
|
|
}
|
|
|
|
|
if authenticated {
|
2018-10-03 05:07:51 +03:00
|
|
|
|
common.Log.Trace("this.authenticated = True")
|
|
|
|
|
crypt.authenticated = true
|
2016-07-09 14:09:27 +00:00
|
|
|
|
return true, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false, nil
|
|
|
|
|
}
|
|
|
|
|
|
2017-07-12 09:48:16 +00:00
|
|
|
|
// Check access rights and permissions for a specified password. If either user/owner password is specified,
|
|
|
|
|
// full rights are granted, otherwise the access rights are specified by the Permissions flag.
|
|
|
|
|
//
|
|
|
|
|
// The bool flag indicates that the user can access and can view the file.
|
|
|
|
|
// The AccessPermissions shows what access the user has for editing etc.
|
|
|
|
|
// An error is returned if there was a problem performing the authentication.
|
2017-08-03 15:13:40 +00:00
|
|
|
|
func (crypt *PdfCrypt) checkAccessRights(password []byte) (bool, AccessPermissions, error) {
|
2017-07-12 09:48:16 +00:00
|
|
|
|
// Try owner password -> full rights.
|
2018-09-16 04:13:24 +03:00
|
|
|
|
var (
|
|
|
|
|
isOwner bool
|
|
|
|
|
err error
|
|
|
|
|
)
|
2018-09-29 04:39:14 +03:00
|
|
|
|
if crypt.encryptStd.R >= 5 {
|
2018-09-16 04:13:24 +03:00
|
|
|
|
var h []byte
|
|
|
|
|
h, err = crypt.alg12(password)
|
|
|
|
|
if err != nil {
|
2018-09-29 00:43:24 +03:00
|
|
|
|
return false, 0, err
|
2018-09-16 04:13:24 +03:00
|
|
|
|
}
|
|
|
|
|
isOwner = len(h) != 0
|
|
|
|
|
} else {
|
2018-09-26 01:08:19 +03:00
|
|
|
|
isOwner, err = crypt.alg7(password)
|
2018-09-16 04:13:24 +03:00
|
|
|
|
}
|
2017-07-12 09:48:16 +00:00
|
|
|
|
if err != nil {
|
2018-09-29 00:43:24 +03:00
|
|
|
|
return false, 0, err
|
2017-07-12 09:48:16 +00:00
|
|
|
|
}
|
|
|
|
|
if isOwner {
|
|
|
|
|
// owner -> full rights.
|
2018-09-29 00:43:24 +03:00
|
|
|
|
return true, PermOwner, nil
|
2017-07-12 09:48:16 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Try user password.
|
2018-09-16 04:13:24 +03:00
|
|
|
|
var isUser bool
|
2018-09-29 04:39:14 +03:00
|
|
|
|
if crypt.encryptStd.R >= 5 {
|
2018-09-16 04:13:24 +03:00
|
|
|
|
var h []byte
|
|
|
|
|
h, err = crypt.alg11(password)
|
|
|
|
|
if err != nil {
|
2018-09-29 00:43:24 +03:00
|
|
|
|
return false, 0, err
|
2018-09-16 04:13:24 +03:00
|
|
|
|
}
|
|
|
|
|
isUser = len(h) != 0
|
|
|
|
|
} else {
|
2018-09-26 01:08:19 +03:00
|
|
|
|
isUser, err = crypt.alg6(password)
|
2018-09-16 04:13:24 +03:00
|
|
|
|
}
|
2017-07-12 09:48:16 +00:00
|
|
|
|
if err != nil {
|
2018-09-29 00:43:24 +03:00
|
|
|
|
return false, 0, err
|
2017-07-12 09:48:16 +00:00
|
|
|
|
}
|
|
|
|
|
if isUser {
|
|
|
|
|
// User password specified correctly -> access granted with specified permissions.
|
2018-09-29 04:39:14 +03:00
|
|
|
|
return true, crypt.encryptStd.P, nil
|
2017-07-12 09:48:16 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Cannot even view the file.
|
2018-09-29 00:43:24 +03:00
|
|
|
|
return false, 0, nil
|
2017-07-12 09:48:16 +00:00
|
|
|
|
}
|
|
|
|
|
|
2017-08-03 15:13:40 +00:00
|
|
|
|
func (crypt *PdfCrypt) paddedPass(pass []byte) []byte {
|
2016-07-09 14:09:27 +00:00
|
|
|
|
key := make([]byte, 32)
|
|
|
|
|
if len(pass) >= 32 {
|
|
|
|
|
for i := 0; i < 32; i++ {
|
|
|
|
|
key[i] = pass[i]
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
for i := 0; i < len(pass); i++ {
|
|
|
|
|
key[i] = pass[i]
|
|
|
|
|
}
|
|
|
|
|
for i := len(pass); i < 32; i++ {
|
|
|
|
|
key[i] = padding[i-len(pass)]
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return key
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Generates a key for encrypting a specific object based on the
|
|
|
|
|
// object and generation number, as well as the document encryption key.
|
2017-08-03 15:13:40 +00:00
|
|
|
|
func (crypt *PdfCrypt) makeKey(filter string, objNum, genNum uint32, ekey []byte) ([]byte, error) {
|
2018-10-03 05:07:51 +03:00
|
|
|
|
f, ok := crypt.cryptFilters[filter]
|
2018-09-29 04:39:14 +03:00
|
|
|
|
if !ok {
|
|
|
|
|
return nil, fmt.Errorf("Unknown crypt filter (%s)", filter)
|
2016-07-09 14:09:27 +00:00
|
|
|
|
}
|
2018-09-25 02:30:16 +03:00
|
|
|
|
return f.MakeKey(objNum, genNum, ekey)
|
2016-07-09 14:09:27 +00:00
|
|
|
|
}
|
|
|
|
|
|
2018-09-29 00:16:57 +03:00
|
|
|
|
// encryptDictKeys list all required field for "Encrypt" dictionary.
|
|
|
|
|
// It is used as a fingerprint to detect old copies of this dictionary.
|
|
|
|
|
var encryptDictKeys = []PdfObjectName{
|
|
|
|
|
"V", "R", "O", "U", "P",
|
|
|
|
|
}
|
|
|
|
|
|
2016-07-09 14:09:27 +00:00
|
|
|
|
// Check if object has already been processed.
|
2017-08-03 15:13:40 +00:00
|
|
|
|
func (crypt *PdfCrypt) isDecrypted(obj PdfObject) bool {
|
2018-10-03 05:07:51 +03:00
|
|
|
|
_, ok := crypt.decryptedObjects[obj]
|
2016-07-09 14:09:27 +00:00
|
|
|
|
if ok {
|
2017-03-02 18:06:32 +00:00
|
|
|
|
common.Log.Trace("Already decrypted")
|
2016-07-09 14:09:27 +00:00
|
|
|
|
return true
|
|
|
|
|
}
|
2018-09-26 04:54:00 +03:00
|
|
|
|
switch obj := obj.(type) {
|
|
|
|
|
case *PdfObjectStream:
|
2018-09-29 04:39:14 +03:00
|
|
|
|
if crypt.encryptStd.R != 5 {
|
2018-09-26 04:54:00 +03:00
|
|
|
|
if name, ok := obj.Get("Type").(*PdfObjectName); ok && *name == "XRef" {
|
|
|
|
|
return true // Cross-reference streams should not be encrypted
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
case *PdfIndirectObject:
|
|
|
|
|
if _, ok = crypt.decryptedObjNum[int(obj.ObjectNumber)]; ok {
|
|
|
|
|
return true
|
|
|
|
|
}
|
2018-09-29 00:16:57 +03:00
|
|
|
|
switch obj := obj.PdfObject.(type) {
|
|
|
|
|
case *PdfObjectDictionary:
|
|
|
|
|
// detect old copies of "Encrypt" dictionary
|
|
|
|
|
// TODO: find a better way to do it
|
|
|
|
|
ok := true
|
|
|
|
|
for _, key := range encryptDictKeys {
|
|
|
|
|
if obj.Get(key) == nil {
|
|
|
|
|
ok = false
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if ok {
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
}
|
2018-09-26 04:54:00 +03:00
|
|
|
|
}
|
2017-08-03 15:13:40 +00:00
|
|
|
|
|
|
|
|
|
common.Log.Trace("Not decrypted yet")
|
|
|
|
|
return false
|
2016-07-09 14:09:27 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Decrypt a buffer with a selected crypt filter.
|
2017-08-03 15:13:40 +00:00
|
|
|
|
func (crypt *PdfCrypt) decryptBytes(buf []byte, filter string, okey []byte) ([]byte, error) {
|
2017-03-02 18:06:32 +00:00
|
|
|
|
common.Log.Trace("Decrypt bytes")
|
2018-10-03 05:07:51 +03:00
|
|
|
|
f, ok := crypt.cryptFilters[filter]
|
2018-09-29 04:39:14 +03:00
|
|
|
|
if !ok {
|
|
|
|
|
return nil, fmt.Errorf("Unknown crypt filter (%s)", filter)
|
2016-07-09 14:09:27 +00:00
|
|
|
|
}
|
2018-09-25 02:30:16 +03:00
|
|
|
|
return f.DecryptBytes(buf, okey)
|
2016-07-09 14:09:27 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Decrypt an object with specified key. For numbered objects,
|
|
|
|
|
// the key argument is not used and a new one is generated based
|
|
|
|
|
// on the object and generation number.
|
|
|
|
|
// Traverses through all the subobjects (recursive).
|
|
|
|
|
//
|
|
|
|
|
// Does not look up references.. That should be done prior to calling.
|
2017-08-03 15:13:40 +00:00
|
|
|
|
func (crypt *PdfCrypt) Decrypt(obj PdfObject, parentObjNum, parentGenNum int64) error {
|
|
|
|
|
if crypt.isDecrypted(obj) {
|
2016-07-09 14:09:27 +00:00
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-20 00:12:58 +03:00
|
|
|
|
switch obj := obj.(type) {
|
|
|
|
|
case *PdfIndirectObject:
|
2018-10-03 05:07:51 +03:00
|
|
|
|
crypt.decryptedObjects[obj] = true
|
2016-07-09 14:09:27 +00:00
|
|
|
|
|
2018-09-20 00:12:58 +03:00
|
|
|
|
common.Log.Trace("Decrypting indirect %d %d obj!", obj.ObjectNumber, obj.GenerationNumber)
|
2016-07-09 14:09:27 +00:00
|
|
|
|
|
2018-09-25 01:39:00 +03:00
|
|
|
|
objNum := obj.ObjectNumber
|
|
|
|
|
genNum := obj.GenerationNumber
|
2016-07-09 14:09:27 +00:00
|
|
|
|
|
2018-09-20 00:12:58 +03:00
|
|
|
|
err := crypt.Decrypt(obj.PdfObject, objNum, genNum)
|
2016-07-09 14:09:27 +00:00
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
return nil
|
2018-09-20 00:12:58 +03:00
|
|
|
|
case *PdfObjectStream:
|
2016-07-09 14:09:27 +00:00
|
|
|
|
// Mark as decrypted first to avoid recursive issues.
|
2018-10-03 05:07:51 +03:00
|
|
|
|
crypt.decryptedObjects[obj] = true
|
2018-09-25 01:39:00 +03:00
|
|
|
|
dict := obj.PdfObjectDictionary
|
|
|
|
|
|
2018-09-29 04:39:14 +03:00
|
|
|
|
if crypt.encryptStd.R != 5 {
|
2018-09-26 04:54:00 +03:00
|
|
|
|
if s, ok := dict.Get("Type").(*PdfObjectName); ok && *s == "XRef" {
|
|
|
|
|
return nil // Cross-reference streams should not be encrypted
|
|
|
|
|
}
|
2018-09-25 01:39:00 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
objNum := obj.ObjectNumber
|
|
|
|
|
genNum := obj.GenerationNumber
|
2017-03-02 18:06:32 +00:00
|
|
|
|
common.Log.Trace("Decrypting stream %d %d !", objNum, genNum)
|
2016-07-09 14:09:27 +00:00
|
|
|
|
|
|
|
|
|
// TODO: Check for crypt filter (V4).
|
|
|
|
|
// The Crypt filter shall be the first filter in the Filter array entry.
|
|
|
|
|
|
2018-09-19 23:48:50 +03:00
|
|
|
|
streamFilter := StandardCryptFilter // Default RC4.
|
2018-09-29 04:39:14 +03:00
|
|
|
|
if crypt.encrypt.V >= 4 {
|
2018-10-03 05:07:51 +03:00
|
|
|
|
streamFilter = crypt.streamFilter
|
|
|
|
|
common.Log.Trace("this.streamFilter = %s", crypt.streamFilter)
|
2016-07-09 14:09:27 +00:00
|
|
|
|
|
2017-07-08 21:04:13 +00:00
|
|
|
|
if filters, ok := dict.Get("Filter").(*PdfObjectArray); ok {
|
2016-07-09 14:09:27 +00:00
|
|
|
|
// Crypt filter can only be the first entry.
|
2018-07-15 17:52:53 +00:00
|
|
|
|
if firstFilter, ok := GetName(filters.Get(0)); ok {
|
2016-07-09 14:09:27 +00:00
|
|
|
|
if *firstFilter == "Crypt" {
|
|
|
|
|
// Crypt filter overriding the default.
|
|
|
|
|
// Default option is Identity.
|
|
|
|
|
streamFilter = "Identity"
|
|
|
|
|
|
|
|
|
|
// Check if valid crypt filter specified in the decode params.
|
2017-07-08 21:04:13 +00:00
|
|
|
|
if decodeParams, ok := dict.Get("DecodeParms").(*PdfObjectDictionary); ok {
|
|
|
|
|
if filterName, ok := decodeParams.Get("Name").(*PdfObjectName); ok {
|
2018-10-03 05:07:51 +03:00
|
|
|
|
if _, ok := crypt.cryptFilters[string(*filterName)]; ok {
|
2017-03-02 18:06:32 +00:00
|
|
|
|
common.Log.Trace("Using stream filter %s", *filterName)
|
2016-07-09 14:09:27 +00:00
|
|
|
|
streamFilter = string(*filterName)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-03-02 18:06:32 +00:00
|
|
|
|
common.Log.Trace("with %s filter", streamFilter)
|
2016-07-09 14:09:27 +00:00
|
|
|
|
if streamFilter == "Identity" {
|
|
|
|
|
// Identity: pass unchanged.
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-25 01:39:00 +03:00
|
|
|
|
err := crypt.Decrypt(dict, objNum, genNum)
|
2016-07-09 14:09:27 +00:00
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
2018-10-03 05:07:51 +03:00
|
|
|
|
okey, err := crypt.makeKey(streamFilter, uint32(objNum), uint32(genNum), crypt.encryptionKey)
|
2016-07-09 14:09:27 +00:00
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-20 00:12:58 +03:00
|
|
|
|
obj.Stream, err = crypt.decryptBytes(obj.Stream, streamFilter, okey)
|
2016-07-09 14:09:27 +00:00
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
// Update the length based on the decrypted stream.
|
2018-09-20 00:12:58 +03:00
|
|
|
|
dict.Set("Length", MakeInteger(int64(len(obj.Stream))))
|
2016-07-09 14:09:27 +00:00
|
|
|
|
|
|
|
|
|
return nil
|
2018-09-20 00:12:58 +03:00
|
|
|
|
case *PdfObjectString:
|
2017-03-02 18:06:32 +00:00
|
|
|
|
common.Log.Trace("Decrypting string!")
|
2016-07-09 14:09:27 +00:00
|
|
|
|
|
2018-09-19 23:48:50 +03:00
|
|
|
|
stringFilter := StandardCryptFilter
|
2018-09-29 04:39:14 +03:00
|
|
|
|
if crypt.encrypt.V >= 4 {
|
2016-07-09 14:09:27 +00:00
|
|
|
|
// Currently only support Identity / RC4.
|
2018-10-03 05:07:51 +03:00
|
|
|
|
common.Log.Trace("with %s filter", crypt.stringFilter)
|
|
|
|
|
if crypt.stringFilter == "Identity" {
|
2016-07-09 14:09:27 +00:00
|
|
|
|
// Identity: pass unchanged: No action.
|
|
|
|
|
return nil
|
|
|
|
|
}
|
2018-10-03 05:07:51 +03:00
|
|
|
|
stringFilter = crypt.stringFilter
|
2016-07-09 14:09:27 +00:00
|
|
|
|
}
|
|
|
|
|
|
2018-10-03 05:07:51 +03:00
|
|
|
|
key, err := crypt.makeKey(stringFilter, uint32(parentObjNum), uint32(parentGenNum), crypt.encryptionKey)
|
2016-07-09 14:09:27 +00:00
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Overwrite the encrypted with decrypted string.
|
2018-09-26 01:08:19 +03:00
|
|
|
|
str := obj.Str()
|
|
|
|
|
decrypted := make([]byte, len(str))
|
2018-07-14 02:25:29 +00:00
|
|
|
|
for i := 0; i < len(str); i++ {
|
|
|
|
|
decrypted[i] = str[i]
|
2016-07-09 14:09:27 +00:00
|
|
|
|
}
|
2017-03-02 18:06:32 +00:00
|
|
|
|
common.Log.Trace("Decrypt string: %s : % x", decrypted, decrypted)
|
2017-08-03 15:13:40 +00:00
|
|
|
|
decrypted, err = crypt.decryptBytes(decrypted, stringFilter, key)
|
2016-07-09 14:09:27 +00:00
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
2018-09-26 01:08:19 +03:00
|
|
|
|
obj.val = string(decrypted)
|
2016-07-09 14:09:27 +00:00
|
|
|
|
|
|
|
|
|
return nil
|
2018-09-20 00:12:58 +03:00
|
|
|
|
case *PdfObjectArray:
|
2018-09-26 01:08:19 +03:00
|
|
|
|
for _, o := range obj.Elements() {
|
2017-08-03 15:13:40 +00:00
|
|
|
|
err := crypt.Decrypt(o, parentObjNum, parentGenNum)
|
2016-07-09 14:09:27 +00:00
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return nil
|
2018-09-20 00:12:58 +03:00
|
|
|
|
case *PdfObjectDictionary:
|
2016-09-28 15:04:11 +00:00
|
|
|
|
isSig := false
|
2018-09-20 00:12:58 +03:00
|
|
|
|
if t := obj.Get("Type"); t != nil {
|
2016-09-28 15:04:11 +00:00
|
|
|
|
typeStr, ok := t.(*PdfObjectName)
|
|
|
|
|
if ok && *typeStr == "Sig" {
|
|
|
|
|
isSig = true
|
|
|
|
|
}
|
|
|
|
|
}
|
2018-09-20 00:12:58 +03:00
|
|
|
|
for _, keyidx := range obj.Keys() {
|
|
|
|
|
o := obj.Get(keyidx)
|
2016-07-09 14:09:27 +00:00
|
|
|
|
// How can we avoid this check, i.e. implement a more smart
|
|
|
|
|
// traversal system?
|
2016-09-28 15:04:11 +00:00
|
|
|
|
if isSig && string(keyidx) == "Contents" {
|
|
|
|
|
// Leave the Contents of a Signature dictionary.
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
|
2016-07-09 14:09:27 +00:00
|
|
|
|
if string(keyidx) != "Parent" && string(keyidx) != "Prev" && string(keyidx) != "Last" { // Check not needed?
|
2017-08-03 15:13:40 +00:00
|
|
|
|
err := crypt.Decrypt(o, parentObjNum, parentGenNum)
|
2016-07-09 14:09:27 +00:00
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Check if object has already been processed.
|
2017-08-03 15:13:40 +00:00
|
|
|
|
func (crypt *PdfCrypt) isEncrypted(obj PdfObject) bool {
|
2018-10-03 05:07:51 +03:00
|
|
|
|
_, ok := crypt.encryptedObjects[obj]
|
2016-07-09 14:09:27 +00:00
|
|
|
|
if ok {
|
2017-03-02 18:06:32 +00:00
|
|
|
|
common.Log.Trace("Already encrypted")
|
2016-07-09 14:09:27 +00:00
|
|
|
|
return true
|
|
|
|
|
}
|
2017-08-03 15:13:40 +00:00
|
|
|
|
|
|
|
|
|
common.Log.Trace("Not encrypted yet")
|
|
|
|
|
return false
|
2016-07-09 14:09:27 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Encrypt a buffer with the specified crypt filter and key.
|
2017-08-03 15:13:40 +00:00
|
|
|
|
func (crypt *PdfCrypt) encryptBytes(buf []byte, filter string, okey []byte) ([]byte, error) {
|
2017-03-02 18:06:32 +00:00
|
|
|
|
common.Log.Trace("Encrypt bytes")
|
2018-10-03 05:07:51 +03:00
|
|
|
|
f, ok := crypt.cryptFilters[filter]
|
2018-09-29 04:39:14 +03:00
|
|
|
|
if !ok {
|
|
|
|
|
return nil, fmt.Errorf("Unknown crypt filter (%s)", filter)
|
2016-07-09 14:09:27 +00:00
|
|
|
|
}
|
2018-09-25 02:30:16 +03:00
|
|
|
|
return f.EncryptBytes(buf, okey)
|
2016-07-09 14:09:27 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Encrypt an object with specified key. For numbered objects,
|
|
|
|
|
// the key argument is not used and a new one is generated based
|
|
|
|
|
// on the object and generation number.
|
|
|
|
|
// Traverses through all the subobjects (recursive).
|
|
|
|
|
//
|
|
|
|
|
// Does not look up references.. That should be done prior to calling.
|
2017-08-03 15:13:40 +00:00
|
|
|
|
func (crypt *PdfCrypt) Encrypt(obj PdfObject, parentObjNum, parentGenNum int64) error {
|
|
|
|
|
if crypt.isEncrypted(obj) {
|
2016-07-09 14:09:27 +00:00
|
|
|
|
return nil
|
|
|
|
|
}
|
2018-09-20 00:12:58 +03:00
|
|
|
|
switch obj := obj.(type) {
|
|
|
|
|
case *PdfIndirectObject:
|
2018-10-03 05:07:51 +03:00
|
|
|
|
crypt.encryptedObjects[obj] = true
|
2016-07-09 14:09:27 +00:00
|
|
|
|
|
2018-09-20 00:12:58 +03:00
|
|
|
|
common.Log.Trace("Encrypting indirect %d %d obj!", obj.ObjectNumber, obj.GenerationNumber)
|
2016-07-09 14:09:27 +00:00
|
|
|
|
|
2018-09-25 01:39:00 +03:00
|
|
|
|
objNum := obj.ObjectNumber
|
|
|
|
|
genNum := obj.GenerationNumber
|
2016-07-09 14:09:27 +00:00
|
|
|
|
|
2018-09-20 00:12:58 +03:00
|
|
|
|
err := crypt.Encrypt(obj.PdfObject, objNum, genNum)
|
2016-07-09 14:09:27 +00:00
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
return nil
|
2018-09-20 00:12:58 +03:00
|
|
|
|
case *PdfObjectStream:
|
2018-10-03 05:07:51 +03:00
|
|
|
|
crypt.encryptedObjects[obj] = true
|
2018-09-25 01:39:00 +03:00
|
|
|
|
dict := obj.PdfObjectDictionary
|
|
|
|
|
|
|
|
|
|
if s, ok := dict.Get("Type").(*PdfObjectName); ok && *s == "XRef" {
|
|
|
|
|
return nil // Cross-reference streams should not be encrypted
|
|
|
|
|
}
|
2016-07-09 14:09:27 +00:00
|
|
|
|
|
2018-09-25 01:39:00 +03:00
|
|
|
|
objNum := obj.ObjectNumber
|
|
|
|
|
genNum := obj.GenerationNumber
|
2017-03-02 18:06:32 +00:00
|
|
|
|
common.Log.Trace("Encrypting stream %d %d !", objNum, genNum)
|
2016-07-09 14:09:27 +00:00
|
|
|
|
|
|
|
|
|
// TODO: Check for crypt filter (V4).
|
|
|
|
|
// The Crypt filter shall be the first filter in the Filter array entry.
|
|
|
|
|
|
2018-09-19 23:48:50 +03:00
|
|
|
|
streamFilter := StandardCryptFilter // Default RC4.
|
2018-09-29 04:39:14 +03:00
|
|
|
|
if crypt.encrypt.V >= 4 {
|
2016-07-09 14:09:27 +00:00
|
|
|
|
// For now. Need to change when we add support for more than
|
|
|
|
|
// Identity / RC4.
|
2018-10-03 05:07:51 +03:00
|
|
|
|
streamFilter = crypt.streamFilter
|
|
|
|
|
common.Log.Trace("this.streamFilter = %s", crypt.streamFilter)
|
2016-07-09 14:09:27 +00:00
|
|
|
|
|
2017-07-08 21:04:13 +00:00
|
|
|
|
if filters, ok := dict.Get("Filter").(*PdfObjectArray); ok {
|
2016-07-09 14:09:27 +00:00
|
|
|
|
// Crypt filter can only be the first entry.
|
2018-07-15 17:52:53 +00:00
|
|
|
|
if firstFilter, ok := GetName(filters.Get(0)); ok {
|
2016-07-09 14:09:27 +00:00
|
|
|
|
if *firstFilter == "Crypt" {
|
|
|
|
|
// Crypt filter overriding the default.
|
|
|
|
|
// Default option is Identity.
|
|
|
|
|
streamFilter = "Identity"
|
|
|
|
|
|
|
|
|
|
// Check if valid crypt filter specified in the decode params.
|
2017-07-08 21:04:13 +00:00
|
|
|
|
if decodeParams, ok := dict.Get("DecodeParms").(*PdfObjectDictionary); ok {
|
|
|
|
|
if filterName, ok := decodeParams.Get("Name").(*PdfObjectName); ok {
|
2018-10-03 05:07:51 +03:00
|
|
|
|
if _, ok := crypt.cryptFilters[string(*filterName)]; ok {
|
2017-03-02 18:06:32 +00:00
|
|
|
|
common.Log.Trace("Using stream filter %s", *filterName)
|
2016-07-09 14:09:27 +00:00
|
|
|
|
streamFilter = string(*filterName)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-03-02 18:06:32 +00:00
|
|
|
|
common.Log.Trace("with %s filter", streamFilter)
|
2016-07-09 14:09:27 +00:00
|
|
|
|
if streamFilter == "Identity" {
|
|
|
|
|
// Identity: pass unchanged.
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-20 00:12:58 +03:00
|
|
|
|
err := crypt.Encrypt(obj.PdfObjectDictionary, objNum, genNum)
|
2016-07-09 14:09:27 +00:00
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
2018-10-03 05:07:51 +03:00
|
|
|
|
okey, err := crypt.makeKey(streamFilter, uint32(objNum), uint32(genNum), crypt.encryptionKey)
|
2016-07-09 14:09:27 +00:00
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-20 00:12:58 +03:00
|
|
|
|
obj.Stream, err = crypt.encryptBytes(obj.Stream, streamFilter, okey)
|
2016-07-09 14:09:27 +00:00
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
// Update the length based on the encrypted stream.
|
2018-09-20 00:12:58 +03:00
|
|
|
|
dict.Set("Length", MakeInteger(int64(len(obj.Stream))))
|
2016-07-09 14:09:27 +00:00
|
|
|
|
|
|
|
|
|
return nil
|
2018-09-20 00:12:58 +03:00
|
|
|
|
case *PdfObjectString:
|
2017-03-02 18:06:32 +00:00
|
|
|
|
common.Log.Trace("Encrypting string!")
|
2016-07-09 14:09:27 +00:00
|
|
|
|
|
2018-09-19 23:48:50 +03:00
|
|
|
|
stringFilter := StandardCryptFilter
|
2018-09-29 04:39:14 +03:00
|
|
|
|
if crypt.encrypt.V >= 4 {
|
2018-10-03 05:07:51 +03:00
|
|
|
|
common.Log.Trace("with %s filter", crypt.stringFilter)
|
|
|
|
|
if crypt.stringFilter == "Identity" {
|
2016-07-09 14:09:27 +00:00
|
|
|
|
// Identity: pass unchanged: No action.
|
|
|
|
|
return nil
|
|
|
|
|
}
|
2018-10-03 05:07:51 +03:00
|
|
|
|
stringFilter = crypt.stringFilter
|
2016-07-09 14:09:27 +00:00
|
|
|
|
}
|
|
|
|
|
|
2018-10-03 05:07:51 +03:00
|
|
|
|
key, err := crypt.makeKey(stringFilter, uint32(parentObjNum), uint32(parentGenNum), crypt.encryptionKey)
|
2016-07-09 14:09:27 +00:00
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-26 01:08:19 +03:00
|
|
|
|
str := obj.Str()
|
2018-07-14 02:25:29 +00:00
|
|
|
|
encrypted := make([]byte, len(str))
|
|
|
|
|
for i := 0; i < len(str); i++ {
|
|
|
|
|
encrypted[i] = str[i]
|
2016-07-09 14:09:27 +00:00
|
|
|
|
}
|
2017-03-02 18:06:32 +00:00
|
|
|
|
common.Log.Trace("Encrypt string: %s : % x", encrypted, encrypted)
|
2017-08-03 15:13:40 +00:00
|
|
|
|
encrypted, err = crypt.encryptBytes(encrypted, stringFilter, key)
|
2016-07-09 14:09:27 +00:00
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
2018-09-26 01:08:19 +03:00
|
|
|
|
obj.val = string(encrypted)
|
2016-07-09 14:09:27 +00:00
|
|
|
|
|
|
|
|
|
return nil
|
2018-09-20 00:12:58 +03:00
|
|
|
|
case *PdfObjectArray:
|
2018-09-26 01:08:19 +03:00
|
|
|
|
for _, o := range obj.Elements() {
|
2017-08-03 15:13:40 +00:00
|
|
|
|
err := crypt.Encrypt(o, parentObjNum, parentGenNum)
|
2016-07-09 14:09:27 +00:00
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return nil
|
2018-09-20 00:12:58 +03:00
|
|
|
|
case *PdfObjectDictionary:
|
2016-09-28 15:04:11 +00:00
|
|
|
|
isSig := false
|
2018-09-20 00:12:58 +03:00
|
|
|
|
if t := obj.Get("Type"); t != nil {
|
2016-09-28 15:04:11 +00:00
|
|
|
|
typeStr, ok := t.(*PdfObjectName)
|
|
|
|
|
if ok && *typeStr == "Sig" {
|
|
|
|
|
isSig = true
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-20 00:12:58 +03:00
|
|
|
|
for _, keyidx := range obj.Keys() {
|
|
|
|
|
o := obj.Get(keyidx)
|
2016-07-09 14:09:27 +00:00
|
|
|
|
// How can we avoid this check, i.e. implement a more smart
|
|
|
|
|
// traversal system?
|
2016-09-28 15:04:11 +00:00
|
|
|
|
if isSig && string(keyidx) == "Contents" {
|
|
|
|
|
// Leave the Contents of a Signature dictionary.
|
|
|
|
|
continue
|
|
|
|
|
}
|
2016-07-09 14:09:27 +00:00
|
|
|
|
if string(keyidx) != "Parent" && string(keyidx) != "Prev" && string(keyidx) != "Last" { // Check not needed?
|
2017-08-03 15:13:40 +00:00
|
|
|
|
err := crypt.Encrypt(o, parentObjNum, parentGenNum)
|
2016-07-09 14:09:27 +00:00
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-19 02:44:26 +03:00
|
|
|
|
// aesZeroIV allocates a zero-filled buffer that serves as an initialization vector for AESv3.
|
|
|
|
|
func (crypt *PdfCrypt) aesZeroIV() []byte {
|
|
|
|
|
if crypt.ivAESZero == nil {
|
|
|
|
|
crypt.ivAESZero = make([]byte, aes.BlockSize)
|
|
|
|
|
}
|
|
|
|
|
return crypt.ivAESZero
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-16 00:34:13 +03:00
|
|
|
|
// alg2a retrieves the encryption key from an encrypted document (R >= 5).
|
|
|
|
|
// It returns false if the password was wrong.
|
2018-09-17 17:36:31 +03:00
|
|
|
|
// 7.6.4.3.2 Algorithm 2.A (page 83)
|
2018-09-16 02:48:08 +03:00
|
|
|
|
func (crypt *PdfCrypt) alg2a(pass []byte) (bool, error) {
|
2018-09-16 00:34:13 +03:00
|
|
|
|
// O & U: 32 byte hash + 8 byte Validation Salt + 8 byte Key Salt
|
|
|
|
|
|
|
|
|
|
// step a: Unicode normalization
|
|
|
|
|
// TODO(dennwc): make sure that UTF-8 strings are normalized
|
|
|
|
|
|
|
|
|
|
// step b: truncate to 127 bytes
|
|
|
|
|
if len(pass) > 127 {
|
|
|
|
|
pass = pass[:127]
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// step c: test pass against the owner key
|
2018-09-16 02:48:08 +03:00
|
|
|
|
h, err := crypt.alg12(pass)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return false, err
|
|
|
|
|
}
|
|
|
|
|
var (
|
|
|
|
|
data []byte // data to hash
|
|
|
|
|
ekey []byte // encrypted file key
|
|
|
|
|
ukey []byte // user key; set only when using owner's password
|
|
|
|
|
)
|
|
|
|
|
if len(h) != 0 {
|
|
|
|
|
// owner password valid
|
|
|
|
|
|
|
|
|
|
// step d: compute an intermediate owner key
|
|
|
|
|
str := make([]byte, len(pass)+8+48)
|
|
|
|
|
i := copy(str, pass)
|
2018-09-29 04:39:14 +03:00
|
|
|
|
i += copy(str[i:], crypt.encryptStd.O[40:48]) // owner Key Salt
|
|
|
|
|
i += copy(str[i:], crypt.encryptStd.U[0:48])
|
2018-09-16 02:48:08 +03:00
|
|
|
|
|
|
|
|
|
data = str
|
2018-09-29 04:39:14 +03:00
|
|
|
|
ekey = crypt.encryptStd.OE
|
|
|
|
|
ukey = crypt.encryptStd.U[0:48]
|
2018-09-16 02:48:08 +03:00
|
|
|
|
} else {
|
|
|
|
|
// check user password
|
|
|
|
|
h, err = crypt.alg11(pass)
|
|
|
|
|
if err == nil && len(h) == 0 {
|
|
|
|
|
// try default password
|
|
|
|
|
h, err = crypt.alg11([]byte(""))
|
|
|
|
|
}
|
|
|
|
|
if err != nil {
|
|
|
|
|
return false, err
|
|
|
|
|
} else if len(h) == 0 {
|
|
|
|
|
// wrong password
|
|
|
|
|
return false, nil
|
|
|
|
|
}
|
|
|
|
|
// step e: compute an intermediate user key
|
|
|
|
|
str := make([]byte, len(pass)+8)
|
|
|
|
|
i := copy(str, pass)
|
2018-09-29 04:39:14 +03:00
|
|
|
|
i += copy(str[i:], crypt.encryptStd.U[40:48]) // user Key Salt
|
2018-09-16 00:34:13 +03:00
|
|
|
|
|
2018-09-16 02:48:08 +03:00
|
|
|
|
data = str
|
2018-09-29 04:39:14 +03:00
|
|
|
|
ekey = crypt.encryptStd.UE
|
2018-09-16 02:48:08 +03:00
|
|
|
|
ukey = nil
|
2018-09-16 00:34:13 +03:00
|
|
|
|
}
|
2018-09-16 02:48:08 +03:00
|
|
|
|
ekey = ekey[:32]
|
|
|
|
|
|
|
|
|
|
// intermediate key
|
2018-09-16 04:13:24 +03:00
|
|
|
|
ikey := crypt.alg2b(data, pass, ukey)
|
2018-09-16 00:34:13 +03:00
|
|
|
|
|
2018-09-16 02:48:08 +03:00
|
|
|
|
ac, err := aes.NewCipher(ikey[:32])
|
2018-09-16 00:34:13 +03:00
|
|
|
|
if err != nil {
|
|
|
|
|
panic(err)
|
|
|
|
|
}
|
2018-09-19 02:44:26 +03:00
|
|
|
|
|
|
|
|
|
iv := crypt.aesZeroIV()
|
2018-09-16 02:48:08 +03:00
|
|
|
|
cbc := cipher.NewCBCDecrypter(ac, iv)
|
2018-09-16 00:34:13 +03:00
|
|
|
|
fkey := make([]byte, 32)
|
2018-09-16 02:48:08 +03:00
|
|
|
|
cbc.CryptBlocks(fkey, ekey)
|
|
|
|
|
|
2018-10-03 05:07:51 +03:00
|
|
|
|
crypt.encryptionKey = fkey
|
2018-09-16 00:34:13 +03:00
|
|
|
|
|
2018-09-29 04:39:14 +03:00
|
|
|
|
if crypt.encryptStd.R == 5 {
|
2018-09-16 04:13:24 +03:00
|
|
|
|
return true, nil
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-16 02:48:08 +03:00
|
|
|
|
return crypt.alg13(fkey)
|
2018-09-16 00:34:13 +03:00
|
|
|
|
}
|
|
|
|
|
|
2018-09-16 04:13:24 +03:00
|
|
|
|
// alg2b computes a hash for R=5 and R=6.
|
|
|
|
|
func (crypt *PdfCrypt) alg2b(data, pwd, userKey []byte) []byte {
|
2018-09-29 04:39:14 +03:00
|
|
|
|
if crypt.encryptStd.R == 5 {
|
2018-09-16 04:13:24 +03:00
|
|
|
|
return alg2b_R5(data)
|
|
|
|
|
}
|
|
|
|
|
return alg2b(data, pwd, userKey)
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-17 17:36:31 +03:00
|
|
|
|
// 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.
|
2018-09-16 00:34:13 +03:00
|
|
|
|
func alg2b_R5(data []byte) []byte {
|
|
|
|
|
h := sha256.New()
|
|
|
|
|
h.Write(data)
|
|
|
|
|
return h.Sum(nil)
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-17 17:36:31 +03:00
|
|
|
|
// 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
|
2018-09-16 17:10:04 +03:00
|
|
|
|
for bp < len(buf) {
|
|
|
|
|
copy(buf[bp:], buf[:bp])
|
|
|
|
|
bp *= 2
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-16 04:13:24 +03:00
|
|
|
|
// alg2b computes a hash for R=6.
|
2018-09-17 17:36:31 +03:00
|
|
|
|
// 7.6.4.3.3 Algorithm 2.B (page 83)
|
2018-09-16 00:34:13 +03:00
|
|
|
|
func alg2b(data, pwd, userKey []byte) []byte {
|
2018-09-16 17:10:04 +03:00
|
|
|
|
var (
|
|
|
|
|
s256, s384, s512 hash.Hash
|
|
|
|
|
)
|
|
|
|
|
s256 = sha256.New()
|
|
|
|
|
hbuf := make([]byte, 64)
|
2018-09-16 00:34:13 +03:00
|
|
|
|
|
2018-09-16 17:10:04 +03:00
|
|
|
|
h := s256
|
|
|
|
|
h.Write(data)
|
|
|
|
|
K := h.Sum(hbuf[:0])
|
|
|
|
|
|
|
|
|
|
buf := make([]byte, 64*(127+64+48))
|
2018-09-16 00:34:13 +03:00
|
|
|
|
|
2018-09-16 17:10:04 +03:00
|
|
|
|
round := func(rnd int) (E []byte) {
|
2018-09-16 00:34:13 +03:00
|
|
|
|
// step a: repeat pass+K 64 times
|
|
|
|
|
n := len(pwd) + len(K) + len(userKey)
|
2018-09-16 17:10:04 +03:00
|
|
|
|
part := buf[:n]
|
2018-09-16 00:34:13 +03:00
|
|
|
|
i := copy(part, pwd)
|
|
|
|
|
i += copy(part[i:], K[:])
|
|
|
|
|
i += copy(part[i:], userKey)
|
|
|
|
|
if i != n {
|
|
|
|
|
panic("wrong size")
|
|
|
|
|
}
|
2018-09-16 17:10:04 +03:00
|
|
|
|
K1 := buf[:n*64]
|
|
|
|
|
repeat(K1, n)
|
2018-09-16 00:34:13 +03:00
|
|
|
|
|
|
|
|
|
// step b: encrypt K1 with AES-128 CBC
|
|
|
|
|
ac, err := aes.NewCipher(K[0:16])
|
|
|
|
|
if err != nil {
|
|
|
|
|
panic(err)
|
|
|
|
|
}
|
|
|
|
|
cbc := cipher.NewCBCEncrypter(ac, K[16:32])
|
|
|
|
|
cbc.CryptBlocks(K1, K1)
|
|
|
|
|
E = K1
|
|
|
|
|
|
|
|
|
|
// step c: use 16 bytes of E as big-endian int, select the next hash
|
|
|
|
|
b := 0
|
|
|
|
|
for i := 0; i < 16; i++ {
|
|
|
|
|
b += int(E[i] % 3)
|
|
|
|
|
}
|
|
|
|
|
var h hash.Hash
|
|
|
|
|
switch b % 3 {
|
|
|
|
|
case 0:
|
2018-09-16 17:10:04 +03:00
|
|
|
|
h = s256
|
2018-09-16 00:34:13 +03:00
|
|
|
|
case 1:
|
2018-09-16 17:10:04 +03:00
|
|
|
|
if s384 == nil {
|
|
|
|
|
s384 = sha512.New384()
|
|
|
|
|
}
|
|
|
|
|
h = s384
|
2018-09-16 00:34:13 +03:00
|
|
|
|
case 2:
|
2018-09-16 17:10:04 +03:00
|
|
|
|
if s512 == nil {
|
|
|
|
|
s512 = sha512.New()
|
|
|
|
|
}
|
|
|
|
|
h = s512
|
2018-09-16 00:34:13 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// step d: take the hash of E, use as a new K
|
|
|
|
|
h.Reset()
|
|
|
|
|
h.Write(E)
|
2018-09-16 17:10:04 +03:00
|
|
|
|
K = h.Sum(hbuf[:0])
|
2018-09-16 00:34:13 +03:00
|
|
|
|
|
|
|
|
|
return E
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for i := 0; ; {
|
|
|
|
|
E := round(i)
|
|
|
|
|
b := uint8(E[len(E)-1])
|
|
|
|
|
// from the spec, it appears that i should be incremented after
|
|
|
|
|
// the test, but that doesn't match what Adobe does
|
|
|
|
|
i++
|
|
|
|
|
if i >= 64 && b <= uint8(i-32) {
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return K[:32]
|
|
|
|
|
}
|
|
|
|
|
|
2018-07-14 02:25:29 +00:00
|
|
|
|
// alg2 computes an encryption key.
|
|
|
|
|
func (crypt *PdfCrypt) alg2(pass []byte) []byte {
|
|
|
|
|
common.Log.Trace("alg2")
|
2017-08-03 15:13:40 +00:00
|
|
|
|
key := crypt.paddedPass(pass)
|
2016-07-09 14:09:27 +00:00
|
|
|
|
|
|
|
|
|
h := md5.New()
|
|
|
|
|
h.Write(key)
|
|
|
|
|
|
|
|
|
|
// Pass O.
|
2018-09-29 04:39:14 +03:00
|
|
|
|
h.Write(crypt.encryptStd.O)
|
2016-07-09 14:09:27 +00:00
|
|
|
|
|
|
|
|
|
// Pass P (Lower order byte first).
|
2018-09-29 04:39:14 +03:00
|
|
|
|
var p = uint32(crypt.encryptStd.P)
|
|
|
|
|
var pb []byte
|
2016-07-09 14:09:27 +00:00
|
|
|
|
for i := 0; i < 4; i++ {
|
|
|
|
|
pb = append(pb, byte(((p >> uint(8*i)) & 0xff)))
|
|
|
|
|
}
|
|
|
|
|
h.Write(pb)
|
2017-03-02 18:06:32 +00:00
|
|
|
|
common.Log.Trace("go P: % x", pb)
|
2016-07-09 14:09:27 +00:00
|
|
|
|
|
|
|
|
|
// Pass ID[0] from the trailer
|
2018-10-03 05:07:51 +03:00
|
|
|
|
h.Write([]byte(crypt.id0))
|
2016-07-09 14:09:27 +00:00
|
|
|
|
|
2018-09-29 04:39:14 +03:00
|
|
|
|
common.Log.Trace("this.R = %d encryptMetadata %v", crypt.encryptStd.R, crypt.encryptStd.EncryptMetadata)
|
|
|
|
|
if (crypt.encryptStd.R >= 4) && !crypt.encryptStd.EncryptMetadata {
|
2016-07-09 14:09:27 +00:00
|
|
|
|
h.Write([]byte{0xff, 0xff, 0xff, 0xff})
|
|
|
|
|
}
|
|
|
|
|
hashb := h.Sum(nil)
|
|
|
|
|
|
2018-09-29 04:39:14 +03:00
|
|
|
|
if crypt.encryptStd.R >= 3 {
|
2016-07-09 14:09:27 +00:00
|
|
|
|
for i := 0; i < 50; i++ {
|
|
|
|
|
h = md5.New()
|
2018-09-29 04:39:14 +03:00
|
|
|
|
h.Write(hashb[0 : crypt.encrypt.Length/8])
|
2016-07-09 14:09:27 +00:00
|
|
|
|
hashb = h.Sum(nil)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-29 04:39:14 +03:00
|
|
|
|
if crypt.encryptStd.R >= 3 {
|
|
|
|
|
return hashb[0 : crypt.encrypt.Length/8]
|
2016-07-09 14:09:27 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return hashb[0:5]
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Create the RC4 encryption key.
|
2017-08-03 15:13:40 +00:00
|
|
|
|
func (crypt *PdfCrypt) alg3Key(pass []byte) []byte {
|
2016-07-09 14:09:27 +00:00
|
|
|
|
h := md5.New()
|
2017-08-03 15:13:40 +00:00
|
|
|
|
okey := crypt.paddedPass(pass)
|
2016-07-09 14:09:27 +00:00
|
|
|
|
h.Write(okey)
|
|
|
|
|
|
2018-09-29 04:39:14 +03:00
|
|
|
|
if crypt.encryptStd.R >= 3 {
|
2016-07-09 14:09:27 +00:00
|
|
|
|
for i := 0; i < 50; i++ {
|
|
|
|
|
hashb := h.Sum(nil)
|
|
|
|
|
h = md5.New()
|
|
|
|
|
h.Write(hashb)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
encKey := h.Sum(nil)
|
2018-09-29 04:39:14 +03:00
|
|
|
|
if crypt.encryptStd.R == 2 {
|
2016-07-09 14:09:27 +00:00
|
|
|
|
encKey = encKey[0:5]
|
|
|
|
|
} else {
|
2018-09-29 04:39:14 +03:00
|
|
|
|
encKey = encKey[0 : crypt.encrypt.Length/8]
|
2016-07-09 14:09:27 +00:00
|
|
|
|
}
|
|
|
|
|
return encKey
|
|
|
|
|
}
|
|
|
|
|
|
2017-08-03 15:13:40 +00:00
|
|
|
|
// Alg3 computes the encryption dictionary’s O (owner password) value.
|
2018-07-14 02:25:29 +00:00
|
|
|
|
func (crypt *PdfCrypt) Alg3(upass, opass []byte) (string, error) {
|
2016-07-09 14:09:27 +00:00
|
|
|
|
// Return O string val.
|
2018-07-14 02:25:29 +00:00
|
|
|
|
O := ""
|
2016-07-09 14:09:27 +00:00
|
|
|
|
|
|
|
|
|
var encKey []byte
|
|
|
|
|
if len(opass) > 0 {
|
2017-08-03 15:13:40 +00:00
|
|
|
|
encKey = crypt.alg3Key(opass)
|
2016-07-09 14:09:27 +00:00
|
|
|
|
} else {
|
2017-08-03 15:13:40 +00:00
|
|
|
|
encKey = crypt.alg3Key(upass)
|
2016-07-09 14:09:27 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ociph, err := rc4.NewCipher(encKey)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return O, errors.New("Failed rc4 ciph")
|
|
|
|
|
}
|
|
|
|
|
|
2017-08-03 15:13:40 +00:00
|
|
|
|
ukey := crypt.paddedPass(upass)
|
2016-07-09 14:09:27 +00:00
|
|
|
|
encrypted := make([]byte, len(ukey))
|
|
|
|
|
ociph.XORKeyStream(encrypted, ukey)
|
|
|
|
|
|
2018-09-29 04:39:14 +03:00
|
|
|
|
if crypt.encryptStd.R >= 3 {
|
2016-07-09 14:09:27 +00:00
|
|
|
|
encKey2 := make([]byte, len(encKey))
|
|
|
|
|
for i := 0; i < 19; i++ {
|
|
|
|
|
for j := 0; j < len(encKey); j++ {
|
|
|
|
|
encKey2[j] = encKey[j] ^ byte(i+1)
|
|
|
|
|
}
|
|
|
|
|
ciph, err := rc4.NewCipher(encKey2)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return O, errors.New("Failed rc4 ciph")
|
|
|
|
|
}
|
|
|
|
|
ciph.XORKeyStream(encrypted, encrypted)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-07-14 02:25:29 +00:00
|
|
|
|
O = string(encrypted)
|
2016-07-09 14:09:27 +00:00
|
|
|
|
return O, nil
|
|
|
|
|
}
|
|
|
|
|
|
2018-07-14 02:25:29 +00:00
|
|
|
|
// alg4 computes the encryption dictionary’s U (user password) value (Security handlers of revision 2).
|
|
|
|
|
func (crypt *PdfCrypt) alg4(upass []byte) (string, []byte, error) {
|
|
|
|
|
U := ""
|
2016-07-09 14:09:27 +00:00
|
|
|
|
|
2018-07-14 02:25:29 +00:00
|
|
|
|
ekey := crypt.alg2(upass)
|
2016-07-09 14:09:27 +00:00
|
|
|
|
ciph, err := rc4.NewCipher(ekey)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return U, ekey, errors.New("Failed rc4 ciph")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
s := []byte(padding)
|
|
|
|
|
encrypted := make([]byte, len(s))
|
|
|
|
|
ciph.XORKeyStream(encrypted, s)
|
|
|
|
|
|
2018-07-14 02:25:29 +00:00
|
|
|
|
U = string(encrypted)
|
2016-07-09 14:09:27 +00:00
|
|
|
|
return U, ekey, nil
|
|
|
|
|
}
|
|
|
|
|
|
2017-08-03 15:13:40 +00:00
|
|
|
|
// Alg5 computes the encryption dictionary’s U (user password) value (Security handlers of revision 3 or greater).
|
2018-07-14 02:25:29 +00:00
|
|
|
|
func (crypt *PdfCrypt) Alg5(upass []byte) (string, []byte, error) {
|
|
|
|
|
U := ""
|
2016-07-09 14:09:27 +00:00
|
|
|
|
|
2018-07-14 02:25:29 +00:00
|
|
|
|
ekey := crypt.alg2(upass)
|
2016-07-09 14:09:27 +00:00
|
|
|
|
|
|
|
|
|
h := md5.New()
|
|
|
|
|
h.Write([]byte(padding))
|
2018-10-03 05:07:51 +03:00
|
|
|
|
h.Write([]byte(crypt.id0))
|
2016-07-09 14:09:27 +00:00
|
|
|
|
hash := h.Sum(nil)
|
|
|
|
|
|
2017-03-02 18:06:32 +00:00
|
|
|
|
common.Log.Trace("Alg5")
|
|
|
|
|
common.Log.Trace("ekey: % x", ekey)
|
2018-10-03 05:07:51 +03:00
|
|
|
|
common.Log.Trace("ID: % x", crypt.id0)
|
2016-07-09 14:09:27 +00:00
|
|
|
|
|
|
|
|
|
if len(hash) != 16 {
|
|
|
|
|
return U, ekey, errors.New("Hash length not 16 bytes")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ciph, err := rc4.NewCipher(ekey)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return U, ekey, errors.New("Failed rc4 ciph")
|
|
|
|
|
}
|
|
|
|
|
encrypted := make([]byte, 16)
|
|
|
|
|
ciph.XORKeyStream(encrypted, hash)
|
|
|
|
|
|
|
|
|
|
// Do the following 19 times: Take the output from the previous
|
|
|
|
|
// invocation of the RC4 function and pass it as input to a new
|
|
|
|
|
// invocation of the function; use an encryption key generated by
|
|
|
|
|
// taking each byte of the original encryption key obtained in step
|
|
|
|
|
// (a) and performing an XOR (exclusive or) operation between that
|
|
|
|
|
// byte and the single-byte value of the iteration counter (from 1 to 19).
|
|
|
|
|
ekey2 := make([]byte, len(ekey))
|
|
|
|
|
for i := 0; i < 19; i++ {
|
|
|
|
|
for j := 0; j < len(ekey); j++ {
|
|
|
|
|
ekey2[j] = ekey[j] ^ byte(i+1)
|
|
|
|
|
}
|
|
|
|
|
ciph, err = rc4.NewCipher(ekey2)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return U, ekey, errors.New("Failed rc4 ciph")
|
|
|
|
|
}
|
|
|
|
|
ciph.XORKeyStream(encrypted, encrypted)
|
2017-03-02 18:06:32 +00:00
|
|
|
|
common.Log.Trace("i = %d, ekey: % x", i, ekey2)
|
|
|
|
|
common.Log.Trace("i = %d -> % x", i, encrypted)
|
2016-07-09 14:09:27 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bb := make([]byte, 32)
|
|
|
|
|
for i := 0; i < 16; i++ {
|
|
|
|
|
bb[i] = encrypted[i]
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Append 16 bytes of arbitrary padding to the output from the final
|
|
|
|
|
// invocation of the RC4 function and store the 32-byte result as
|
|
|
|
|
// the value of the U entry in the encryption dictionary.
|
|
|
|
|
_, err = rand.Read(bb[16:32])
|
|
|
|
|
if err != nil {
|
|
|
|
|
return U, ekey, errors.New("Failed to gen rand number")
|
|
|
|
|
}
|
|
|
|
|
|
2018-07-14 02:25:29 +00:00
|
|
|
|
U = string(bb)
|
2016-07-09 14:09:27 +00:00
|
|
|
|
return U, ekey, nil
|
|
|
|
|
}
|
|
|
|
|
|
2018-07-14 02:25:29 +00:00
|
|
|
|
// alg6 authenticates the user password.
|
|
|
|
|
func (crypt *PdfCrypt) alg6(upass []byte) (bool, error) {
|
|
|
|
|
var uo string
|
2016-07-09 14:09:27 +00:00
|
|
|
|
var err error
|
|
|
|
|
var key []byte
|
2018-09-29 04:39:14 +03:00
|
|
|
|
if crypt.encryptStd.R == 2 {
|
2018-07-14 02:25:29 +00:00
|
|
|
|
uo, key, err = crypt.alg4(upass)
|
2018-09-29 04:39:14 +03:00
|
|
|
|
} else if crypt.encryptStd.R >= 3 {
|
2017-08-03 15:13:40 +00:00
|
|
|
|
uo, key, err = crypt.Alg5(upass)
|
2016-07-09 14:09:27 +00:00
|
|
|
|
} else {
|
|
|
|
|
return false, errors.New("invalid R")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
return false, err
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-29 04:39:14 +03:00
|
|
|
|
common.Log.Trace("check: % x == % x ?", string(uo), string(crypt.encryptStd.U))
|
2016-07-09 14:09:27 +00:00
|
|
|
|
|
2018-09-29 04:39:14 +03:00
|
|
|
|
uGen := string(uo) // Generated U from specified pass.
|
|
|
|
|
uDoc := string(crypt.encryptStd.U) // U from the document.
|
|
|
|
|
if crypt.encryptStd.R >= 3 {
|
2016-07-09 14:09:27 +00:00
|
|
|
|
// comparing on the first 16 bytes in the case of security
|
|
|
|
|
// handlers of revision 3 or greater),
|
2017-07-23 20:20:05 +00:00
|
|
|
|
if len(uGen) > 16 {
|
|
|
|
|
uGen = uGen[0:16]
|
|
|
|
|
}
|
|
|
|
|
if len(uDoc) > 16 {
|
|
|
|
|
uDoc = uDoc[0:16]
|
|
|
|
|
}
|
2016-07-09 14:09:27 +00:00
|
|
|
|
}
|
2017-08-03 15:13:40 +00:00
|
|
|
|
|
2016-07-09 14:09:27 +00:00
|
|
|
|
if uGen == uDoc {
|
2018-10-03 05:07:51 +03:00
|
|
|
|
crypt.encryptionKey = key
|
2016-07-09 14:09:27 +00:00
|
|
|
|
return true, nil
|
|
|
|
|
}
|
2017-08-03 15:13:40 +00:00
|
|
|
|
|
|
|
|
|
return false, nil
|
2016-07-09 14:09:27 +00:00
|
|
|
|
}
|
|
|
|
|
|
2018-07-14 02:25:29 +00:00
|
|
|
|
// alg7 authenticates the owner password.
|
|
|
|
|
func (crypt *PdfCrypt) alg7(opass []byte) (bool, error) {
|
2017-08-03 15:13:40 +00:00
|
|
|
|
encKey := crypt.alg3Key(opass)
|
2016-07-09 14:09:27 +00:00
|
|
|
|
|
2018-09-29 04:39:14 +03:00
|
|
|
|
decrypted := make([]byte, len(crypt.encryptStd.O))
|
|
|
|
|
if crypt.encryptStd.R == 2 {
|
2016-07-09 14:09:27 +00:00
|
|
|
|
ciph, err := rc4.NewCipher(encKey)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return false, errors.New("Failed cipher")
|
|
|
|
|
}
|
2018-09-29 04:39:14 +03:00
|
|
|
|
ciph.XORKeyStream(decrypted, crypt.encryptStd.O)
|
|
|
|
|
} else if crypt.encryptStd.R >= 3 {
|
|
|
|
|
s := append([]byte{}, crypt.encryptStd.O...)
|
2016-07-09 14:09:27 +00:00
|
|
|
|
for i := 0; i < 20; i++ {
|
2017-07-12 09:48:16 +00:00
|
|
|
|
//newKey := encKey
|
|
|
|
|
newKey := append([]byte{}, encKey...)
|
2016-07-09 14:09:27 +00:00
|
|
|
|
for j := 0; j < len(encKey); j++ {
|
2017-07-12 09:48:16 +00:00
|
|
|
|
newKey[j] ^= byte(19 - i)
|
2016-07-09 14:09:27 +00:00
|
|
|
|
}
|
|
|
|
|
ciph, err := rc4.NewCipher(newKey)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return false, errors.New("Failed cipher")
|
|
|
|
|
}
|
|
|
|
|
ciph.XORKeyStream(decrypted, s)
|
2017-07-12 09:48:16 +00:00
|
|
|
|
s = append([]byte{}, decrypted...)
|
2016-07-09 14:09:27 +00:00
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
return false, errors.New("invalid R")
|
|
|
|
|
}
|
|
|
|
|
|
2018-07-14 02:25:29 +00:00
|
|
|
|
auth, err := crypt.alg6(decrypted)
|
2017-07-12 09:48:16 +00:00
|
|
|
|
if err != nil {
|
2016-07-09 14:09:27 +00:00
|
|
|
|
return false, nil
|
|
|
|
|
}
|
2017-07-12 09:48:16 +00:00
|
|
|
|
|
|
|
|
|
return auth, nil
|
2016-07-09 14:09:27 +00:00
|
|
|
|
}
|
2018-09-16 00:34:13 +03:00
|
|
|
|
|
2018-09-19 06:02:15 +03:00
|
|
|
|
// GenerateParams generates encryption parameters for specified passwords.
|
|
|
|
|
// Can be called only for R>=5.
|
|
|
|
|
func (crypt *PdfCrypt) GenerateParams(upass, opass []byte) error {
|
2018-09-29 04:39:14 +03:00
|
|
|
|
if crypt.encryptStd.R < 5 {
|
2018-09-19 06:02:15 +03:00
|
|
|
|
// TODO(dennwc): move code for R<5 from PdfWriter.Encrypt
|
|
|
|
|
return errors.New("can be used only for R>=5")
|
|
|
|
|
}
|
2018-10-03 05:07:51 +03:00
|
|
|
|
crypt.encryptionKey = make([]byte, 32)
|
|
|
|
|
if _, err := io.ReadFull(rand.Reader, crypt.encryptionKey); err != nil {
|
2018-09-19 06:02:15 +03:00
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
return crypt.generateR6(upass, opass)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// generateR6 is the algorithm opposite to alg2a (R>=5).
|
2018-09-19 03:33:59 +03:00
|
|
|
|
// It generates U,O,UE,OE,Perms fields using AESv3 encryption.
|
|
|
|
|
// There is no algorithm number assigned to this function in the spec.
|
2018-09-19 06:02:15 +03:00
|
|
|
|
func (crypt *PdfCrypt) generateR6(upass, opass []byte) error {
|
2018-09-19 03:33:59 +03:00
|
|
|
|
// all these field will be populated by functions below
|
2018-09-29 04:39:14 +03:00
|
|
|
|
crypt.encryptStd.U = nil
|
|
|
|
|
crypt.encryptStd.O = nil
|
|
|
|
|
crypt.encryptStd.UE = nil
|
|
|
|
|
crypt.encryptStd.OE = nil
|
|
|
|
|
crypt.encryptStd.Perms = nil // populated only for R=6
|
2018-09-19 03:33:59 +03:00
|
|
|
|
|
|
|
|
|
if len(upass) > 127 {
|
|
|
|
|
upass = upass[:127]
|
|
|
|
|
}
|
|
|
|
|
if len(opass) > 127 {
|
|
|
|
|
opass = opass[:127]
|
|
|
|
|
}
|
|
|
|
|
// generate U and UE
|
|
|
|
|
if err := crypt.alg8(upass); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
// generate O and OE
|
|
|
|
|
if err := crypt.alg9(opass); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
2018-09-29 04:39:14 +03:00
|
|
|
|
if crypt.encryptStd.R == 5 {
|
2018-09-19 03:33:59 +03:00
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
// generate Perms
|
|
|
|
|
return crypt.alg10()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// alg8 computes the encryption dictionary's U (user password) and UE (user encryption) values (R>=5).
|
|
|
|
|
// 7.6.4.4.6 Algorithm 8 (page 86)
|
|
|
|
|
func (crypt *PdfCrypt) alg8(upass []byte) error {
|
|
|
|
|
// step a: compute U (user password)
|
|
|
|
|
var rbuf [16]byte
|
|
|
|
|
if _, err := io.ReadFull(rand.Reader, rbuf[:]); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
valSalt := rbuf[0:8]
|
|
|
|
|
keySalt := rbuf[8:16]
|
|
|
|
|
|
|
|
|
|
str := make([]byte, len(upass)+len(valSalt))
|
|
|
|
|
i := copy(str, upass)
|
|
|
|
|
i += copy(str[i:], valSalt)
|
|
|
|
|
|
|
|
|
|
h := crypt.alg2b(str, upass, nil)
|
|
|
|
|
|
|
|
|
|
U := make([]byte, len(h)+len(valSalt)+len(keySalt))
|
|
|
|
|
i = copy(U, h[:32])
|
|
|
|
|
i += copy(U[i:], valSalt)
|
|
|
|
|
i += copy(U[i:], keySalt)
|
|
|
|
|
|
2018-09-29 04:39:14 +03:00
|
|
|
|
crypt.encryptStd.U = U
|
2018-09-19 03:33:59 +03:00
|
|
|
|
|
|
|
|
|
// step b: compute UE (user encryption)
|
|
|
|
|
|
|
|
|
|
// str still contains a password, reuse it
|
|
|
|
|
i = len(upass)
|
|
|
|
|
i += copy(str[i:], keySalt)
|
|
|
|
|
|
|
|
|
|
h = crypt.alg2b(str, upass, nil)
|
|
|
|
|
|
|
|
|
|
ac, err := aes.NewCipher(h[:32])
|
|
|
|
|
if err != nil {
|
|
|
|
|
panic(err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
iv := crypt.aesZeroIV()
|
|
|
|
|
cbc := cipher.NewCBCEncrypter(ac, iv)
|
|
|
|
|
UE := make([]byte, 32)
|
2018-10-03 05:07:51 +03:00
|
|
|
|
cbc.CryptBlocks(UE, crypt.encryptionKey[:32])
|
2018-09-29 04:39:14 +03:00
|
|
|
|
crypt.encryptStd.UE = UE
|
2018-09-19 03:33:59 +03:00
|
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// alg9 computes the encryption dictionary's O (owner password) and OE (owner encryption) values (R>=5).
|
|
|
|
|
// 7.6.4.4.7 Algorithm 9 (page 86)
|
|
|
|
|
func (crypt *PdfCrypt) alg9(opass []byte) error {
|
|
|
|
|
// step a: compute O (owner password)
|
|
|
|
|
var rbuf [16]byte
|
|
|
|
|
if _, err := io.ReadFull(rand.Reader, rbuf[:]); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
valSalt := rbuf[0:8]
|
|
|
|
|
keySalt := rbuf[8:16]
|
2018-09-29 04:39:14 +03:00
|
|
|
|
userKey := crypt.encryptStd.U[:48]
|
2018-09-19 03:33:59 +03:00
|
|
|
|
|
|
|
|
|
str := make([]byte, len(opass)+len(valSalt)+len(userKey))
|
|
|
|
|
i := copy(str, opass)
|
|
|
|
|
i += copy(str[i:], valSalt)
|
|
|
|
|
i += copy(str[i:], userKey)
|
|
|
|
|
|
|
|
|
|
h := crypt.alg2b(str, opass, userKey)
|
|
|
|
|
|
|
|
|
|
O := make([]byte, len(h)+len(valSalt)+len(keySalt))
|
|
|
|
|
i = copy(O, h[:32])
|
|
|
|
|
i += copy(O[i:], valSalt)
|
|
|
|
|
i += copy(O[i:], keySalt)
|
|
|
|
|
|
2018-09-29 04:39:14 +03:00
|
|
|
|
crypt.encryptStd.O = O
|
2018-09-19 03:33:59 +03:00
|
|
|
|
|
|
|
|
|
// step b: compute OE (owner encryption)
|
|
|
|
|
|
|
|
|
|
// str still contains a password and a user key - reuse both, but overwrite the salt
|
|
|
|
|
i = len(opass)
|
|
|
|
|
i += copy(str[i:], keySalt)
|
|
|
|
|
// i += len(userKey)
|
|
|
|
|
|
|
|
|
|
h = crypt.alg2b(str, opass, userKey)
|
|
|
|
|
|
|
|
|
|
ac, err := aes.NewCipher(h[:32])
|
|
|
|
|
if err != nil {
|
|
|
|
|
panic(err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
iv := crypt.aesZeroIV()
|
|
|
|
|
cbc := cipher.NewCBCEncrypter(ac, iv)
|
|
|
|
|
OE := make([]byte, 32)
|
2018-10-03 05:07:51 +03:00
|
|
|
|
cbc.CryptBlocks(OE, crypt.encryptionKey[:32])
|
2018-09-29 04:39:14 +03:00
|
|
|
|
crypt.encryptStd.OE = OE
|
2018-09-19 03:33:59 +03:00
|
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// alg10 computes the encryption dictionary's Perms (permissions) value (R=6).
|
|
|
|
|
// 7.6.4.4.8 Algorithm 10 (page 87)
|
|
|
|
|
func (crypt *PdfCrypt) alg10() error {
|
|
|
|
|
// step a: extend permissions to 64 bits
|
2018-09-29 04:39:14 +03:00
|
|
|
|
perms := uint64(uint32(crypt.encryptStd.P)) | (math.MaxUint32 << 32)
|
2018-09-19 03:33:59 +03:00
|
|
|
|
|
|
|
|
|
// step b: record permissions
|
|
|
|
|
Perms := make([]byte, 16)
|
|
|
|
|
binary.LittleEndian.PutUint64(Perms[:8], perms)
|
|
|
|
|
|
|
|
|
|
// step c: record EncryptMetadata
|
2018-09-29 04:39:14 +03:00
|
|
|
|
if crypt.encryptStd.EncryptMetadata {
|
2018-09-19 03:33:59 +03:00
|
|
|
|
Perms[8] = 'T'
|
|
|
|
|
} else {
|
|
|
|
|
Perms[8] = 'F'
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// step d: write "adb" magic
|
|
|
|
|
copy(Perms[9:12], "adb")
|
|
|
|
|
|
|
|
|
|
// step e: write 4 bytes of random data
|
|
|
|
|
|
|
|
|
|
// spec doesn't specify them as generated "from a strong random source",
|
|
|
|
|
// but we will use the cryptographic random generator anyway
|
|
|
|
|
if _, err := io.ReadFull(rand.Reader, Perms[12:16]); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// step f: encrypt permissions
|
2018-10-03 05:07:51 +03:00
|
|
|
|
ac, err := aes.NewCipher(crypt.encryptionKey[:32])
|
2018-09-19 03:33:59 +03:00
|
|
|
|
if err != nil {
|
|
|
|
|
panic(err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ecb := newECBEncrypter(ac)
|
|
|
|
|
ecb.CryptBlocks(Perms, Perms)
|
|
|
|
|
|
2018-09-29 04:39:14 +03:00
|
|
|
|
crypt.encryptStd.Perms = Perms[:16]
|
2018-09-19 03:33:59 +03:00
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-16 02:48:08 +03:00
|
|
|
|
// alg11 authenticates the user password (R >= 5) and returns the hash.
|
|
|
|
|
func (crypt *PdfCrypt) alg11(upass []byte) ([]byte, error) {
|
2018-09-16 00:34:13 +03:00
|
|
|
|
str := make([]byte, len(upass)+8)
|
|
|
|
|
i := copy(str, upass)
|
2018-09-29 04:39:14 +03:00
|
|
|
|
i += copy(str[i:], crypt.encryptStd.U[32:40]) // user Validation Salt
|
2018-09-16 00:34:13 +03:00
|
|
|
|
|
2018-09-16 04:13:24 +03:00
|
|
|
|
h := crypt.alg2b(str, upass, nil)
|
2018-09-16 02:48:08 +03:00
|
|
|
|
h = h[:32]
|
2018-09-29 04:39:14 +03:00
|
|
|
|
if !bytes.Equal(h, crypt.encryptStd.U[:32]) {
|
2018-09-16 02:48:08 +03:00
|
|
|
|
return nil, nil
|
2018-09-16 00:34:13 +03:00
|
|
|
|
}
|
2018-09-16 02:48:08 +03:00
|
|
|
|
return h, nil
|
2018-09-16 00:34:13 +03:00
|
|
|
|
}
|
|
|
|
|
|
2018-09-16 02:48:08 +03:00
|
|
|
|
// alg12 authenticates the owner password (R >= 5) and returns the hash.
|
2018-09-17 17:36:31 +03:00
|
|
|
|
// 7.6.4.4.10 Algorithm 12 (page 87)
|
2018-09-16 02:48:08 +03:00
|
|
|
|
func (crypt *PdfCrypt) alg12(opass []byte) ([]byte, error) {
|
2018-09-16 00:34:13 +03:00
|
|
|
|
str := make([]byte, len(opass)+8+48)
|
|
|
|
|
i := copy(str, opass)
|
2018-09-29 04:39:14 +03:00
|
|
|
|
i += copy(str[i:], crypt.encryptStd.O[32:40]) // owner Validation Salt
|
|
|
|
|
i += copy(str[i:], crypt.encryptStd.U[0:48])
|
2018-09-16 00:34:13 +03:00
|
|
|
|
|
2018-09-29 04:39:14 +03:00
|
|
|
|
h := crypt.alg2b(str, opass, crypt.encryptStd.U[0:48])
|
2018-09-16 02:48:08 +03:00
|
|
|
|
h = h[:32]
|
2018-09-29 04:39:14 +03:00
|
|
|
|
if !bytes.Equal(h, crypt.encryptStd.O[:32]) {
|
2018-09-16 02:48:08 +03:00
|
|
|
|
return nil, nil
|
|
|
|
|
}
|
|
|
|
|
return h, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// alg13 validates user permissions (P+EncryptMetadata vs Perms) for R=6.
|
2018-09-17 17:36:31 +03:00
|
|
|
|
// 7.6.4.4.11 Algorithm 13 (page 87)
|
2018-09-16 02:48:08 +03:00
|
|
|
|
func (crypt *PdfCrypt) alg13(fkey []byte) (bool, error) {
|
2018-09-19 03:12:49 +03:00
|
|
|
|
perms := make([]byte, 16)
|
2018-09-29 04:39:14 +03:00
|
|
|
|
copy(perms, crypt.encryptStd.Perms[:16])
|
2018-09-16 02:48:08 +03:00
|
|
|
|
|
|
|
|
|
ac, err := aes.NewCipher(fkey[:32])
|
|
|
|
|
if err != nil {
|
|
|
|
|
panic(err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ecb := newECBDecrypter(ac)
|
|
|
|
|
ecb.CryptBlocks(perms, perms)
|
|
|
|
|
|
|
|
|
|
if !bytes.Equal(perms[9:12], []byte("adb")) {
|
|
|
|
|
return false, errors.New("decoded permissions are invalid")
|
|
|
|
|
}
|
2018-09-29 00:43:24 +03:00
|
|
|
|
p := AccessPermissions(binary.LittleEndian.Uint32(perms[0:4]))
|
2018-09-29 04:39:14 +03:00
|
|
|
|
if p != crypt.encryptStd.P {
|
2018-09-16 02:48:08 +03:00
|
|
|
|
return false, errors.New("permissions validation failed")
|
2018-09-16 00:34:13 +03:00
|
|
|
|
}
|
2018-09-19 02:43:32 +03:00
|
|
|
|
encMeta := true
|
|
|
|
|
if perms[8] == 'T' {
|
|
|
|
|
encMeta = true
|
|
|
|
|
} else if perms[8] == 'F' {
|
|
|
|
|
encMeta = false
|
|
|
|
|
} else {
|
|
|
|
|
return false, errors.New("decoded metadata encryption flag is invalid")
|
|
|
|
|
}
|
2018-09-29 04:39:14 +03:00
|
|
|
|
if encMeta != crypt.encryptStd.EncryptMetadata {
|
2018-09-19 02:43:32 +03:00
|
|
|
|
return false, errors.New("metadata encryption validation failed")
|
|
|
|
|
}
|
2018-09-16 00:34:13 +03:00
|
|
|
|
return true, nil
|
|
|
|
|
}
|