core: split security handlers into a separate package

This commit is contained in:
Denys Smirnov 2018-10-04 04:33:32 +03:00
parent 006e5f9e6e
commit 42df346e69
13 changed files with 225 additions and 215 deletions

View File

@ -10,10 +10,10 @@ import (
"crypto/rand"
"errors"
"fmt"
"math"
"time"
"github.com/unidoc/unidoc/common"
"github.com/unidoc/unidoc/pdf/core/security"
)
type Version struct {
@ -28,11 +28,11 @@ type EncryptInfo struct {
}
// PdfCryptNewEncrypt makes the document crypt handler based on a specified crypt filter.
func PdfCryptNewEncrypt(cf CryptFilter, userPass, ownerPass []byte, perm AccessPermissions) (*PdfCrypt, *EncryptInfo, error) {
func PdfCryptNewEncrypt(cf CryptFilter, userPass, ownerPass []byte, perm security.Permissions) (*PdfCrypt, *EncryptInfo, error) {
crypter := &PdfCrypt{
encryptedObjects: make(map[PdfObject]bool),
cryptFilters: make(cryptFilters),
encryptStd: stdEncryptDict{
encryptStd: security.StdEncryptDict{
P: perm,
EncryptMetadata: true,
},
@ -83,7 +83,7 @@ func PdfCryptNewEncrypt(cf CryptFilter, userPass, ownerPass []byte, perm AccessP
return nil, nil, err
}
// encode parameters generated by the Standard security handler
crypter.encryptStd.EncodeTo(ed)
encodeEncryptStd(&crypter.encryptStd, ed)
if crypter.encrypt.V >= 4 {
if err := crypter.saveCryptFilters(ed); err != nil {
return nil, nil, err
@ -97,12 +97,115 @@ func PdfCryptNewEncrypt(cf CryptFilter, userPass, ownerPass []byte, perm AccessP
}, nil
}
// encodeEncryptStd encodes fields of standard security handler to an Encrypt dictionary.
func encodeEncryptStd(d *security.StdEncryptDict, ed *PdfObjectDictionary) {
ed.Set("R", MakeInteger(int64(d.R)))
ed.Set("P", MakeInteger(int64(d.P)))
ed.Set("O", MakeStringFromBytes(d.O))
ed.Set("U", MakeStringFromBytes(d.U))
if d.R >= 5 {
ed.Set("OE", MakeStringFromBytes(d.OE))
ed.Set("UE", MakeStringFromBytes(d.UE))
ed.Set("EncryptMetadata", MakeBool(d.EncryptMetadata))
if d.R > 5 {
ed.Set("Perms", MakeStringFromBytes(d.Perms))
}
}
}
// decodeEncryptStd decodes fields of standard security handler from an Encrypt dictionary.
func decodeEncryptStd(d *security.StdEncryptDict, ed *PdfObjectDictionary) error {
// TODO(dennwc): this code is too verbose; maybe use reflection to populate fields and validate afterwards?
R, ok := ed.Get("R").(*PdfObjectInteger)
if !ok {
return errors.New("encrypt dictionary missing R")
}
// TODO(dennwc): according to spec, R should be validated according to V value
if *R < 2 || *R > 6 {
return fmt.Errorf("invalid R (%d)", *R)
}
d.R = int(*R)
O, ok := ed.GetString("O")
if !ok {
return errors.New("encrypt dictionary missing O")
}
if d.R == 5 || d.R == 6 {
// the spec says =48 bytes, but Acrobat pads them out longer
if len(O) < 48 {
return fmt.Errorf("Length(O) < 48 (%d)", len(O))
}
} else if len(O) != 32 {
return fmt.Errorf("Length(O) != 32 (%d)", len(O))
}
d.O = []byte(O)
U, ok := ed.GetString("U")
if !ok {
return errors.New("encrypt dictionary missing U")
}
if d.R == 5 || d.R == 6 {
// the spec says =48 bytes, but Acrobat pads them out longer
if len(U) < 48 {
return fmt.Errorf("Length(U) < 48 (%d)", len(U))
}
} else if len(U) != 32 {
// Strictly this does not cause an error.
// If O is OK and others then can still read the file.
common.Log.Debug("Warning: Length(U) != 32 (%d)", len(U))
//return crypter, errors.New("Length(U) != 32")
}
d.U = []byte(U)
if d.R >= 5 {
OE, ok := ed.GetString("OE")
if !ok {
return errors.New("encrypt dictionary missing OE")
} else if len(OE) != 32 {
return fmt.Errorf("Length(OE) != 32 (%d)", len(OE))
}
d.OE = []byte(OE)
UE, ok := ed.GetString("UE")
if !ok {
return errors.New("encrypt dictionary missing UE")
} else if len(UE) != 32 {
return fmt.Errorf("Length(UE) != 32 (%d)", len(UE))
}
d.UE = []byte(UE)
}
P, ok := ed.Get("P").(*PdfObjectInteger)
if !ok {
return errors.New("encrypt dictionary missing permissions attr")
}
d.P = security.Permissions(*P)
if d.R == 6 {
Perms, ok := ed.GetString("Perms")
if !ok {
return errors.New("encrypt dictionary missing Perms")
} else if len(Perms) != 16 {
return fmt.Errorf("Length(Perms) != 16 (%d)", len(Perms))
}
d.Perms = []byte(Perms)
}
if em, ok := ed.Get("EncryptMetadata").(*PdfObjectBool); ok {
d.EncryptMetadata = bool(*em)
} else {
d.EncryptMetadata = true // True by default.
}
return nil
}
// PdfCrypt provides PDF encryption/decryption support.
// The PDF standard supports encryption of strings and streams (Section 7.6).
// TODO (v3): Consider unexporting.
type PdfCrypt struct {
encrypt encryptDict
encryptStd stdEncryptDict
encryptStd security.StdEncryptDict
id0 string
encryptionKey []byte
@ -117,7 +220,6 @@ type PdfCrypt struct {
parser *PdfParser
decryptedObjNum map[int]struct{}
ivAESZero []byte // a zero buffer used as an initialization vector for AES
}
func (crypt *PdfCrypt) newEncyptDict() *PdfObjectDictionary {
@ -181,35 +283,6 @@ type encryptDict struct {
EFF string // The filter that shall be used when decrypting embedded file streams.
}
// AccessPermissions is a bitmask of access permissions for a PDF file.
type AccessPermissions uint32
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
)
// Allowed checks if a set of permissions can be granted.
func (p AccessPermissions) Allowed(p2 AccessPermissions) bool {
return p&p2 == p2
}
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"
// StandardCryptFilter is a default name for a standard crypt filter.
const StandardCryptFilter = "StdCF"
@ -405,7 +478,7 @@ func PdfCryptNewDecrypt(parser *PdfParser, ed, trailer *PdfObjectDictionary) (*P
}
// decode Standard security handler parameters
if err := crypter.encryptStd.DecodeFrom(ed); err != nil {
if err := decodeEncryptStd(&crypter.encryptStd, ed); err != nil {
return crypter, err
}
@ -428,18 +501,15 @@ func PdfCryptNewDecrypt(parser *PdfParser, ed, trailer *PdfObjectDictionary) (*P
}
// GetAccessPermissions returns the PDF access permissions as an AccessPermissions object.
func (crypt *PdfCrypt) GetAccessPermissions() AccessPermissions {
func (crypt *PdfCrypt) GetAccessPermissions() security.Permissions {
return crypt.encryptStd.P
}
func (crypt *PdfCrypt) securityHandler() stdSecurityHandler {
func (crypt *PdfCrypt) securityHandler() security.StdHandler {
if crypt.encryptStd.R >= 5 {
return stdHandlerR6{}
}
return stdHandlerR4{
ID0: crypt.id0,
Length: crypt.encrypt.Length,
return security.NewHandlerR6()
}
return security.NewHandlerR4(crypt.id0, crypt.encrypt.Length)
}
// Check whether the specified password can be used to decrypt the document.
@ -464,7 +534,7 @@ func (crypt *PdfCrypt) authenticate(password []byte) (bool, error) {
// 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.
func (crypt *PdfCrypt) checkAccessRights(password []byte) (bool, AccessPermissions, error) {
func (crypt *PdfCrypt) checkAccessRights(password []byte) (bool, security.Permissions, error) {
h := crypt.securityHandler()
// TODO(dennwc): it computes an encryption key as well; if necessary, define a new interface method to optimize this
fkey, perm, err := h.Authenticate(&crypt.encryptStd, password)

View File

@ -1,139 +0,0 @@
/*
* 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 (
"errors"
"fmt"
"github.com/unidoc/unidoc/common"
)
type stdSecurityHandler interface {
// GenerateParams uses owner and user passwords to set encryption parameters and generate an encryption key.
// It assumes that R, P and EncryptMetadata are already set.
GenerateParams(d *stdEncryptDict, ownerPass, userPass []byte) ([]byte, error)
// Authenticate uses encryption dictionary parameters and the password to calculate
// the document encryption key. It also returns permissions that should be granted to a user.
// In case of failed authentication, it returns empty key and zero permissions with no error.
Authenticate(d *stdEncryptDict, pass []byte) ([]byte, AccessPermissions, error)
}
// 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.
P AccessPermissions
EncryptMetadata bool // Indicates whether the document-level metadata stream shall be encrypted.
// set by security handlers:
O, U []byte
OE, UE []byte // R=6
Perms []byte // An encrypted copy of P (16 bytes). Used to verify permissions. R=6
}
func (d *stdEncryptDict) EncodeTo(ed *PdfObjectDictionary) {
ed.Set("R", MakeInteger(int64(d.R)))
ed.Set("P", MakeInteger(int64(d.P)))
ed.Set("O", MakeStringFromBytes(d.O))
ed.Set("U", MakeStringFromBytes(d.U))
if d.R >= 5 {
ed.Set("OE", MakeStringFromBytes(d.OE))
ed.Set("UE", MakeStringFromBytes(d.UE))
ed.Set("EncryptMetadata", MakeBool(d.EncryptMetadata))
if d.R > 5 {
ed.Set("Perms", MakeStringFromBytes(d.Perms))
}
}
}
func (d *stdEncryptDict) DecodeFrom(ed *PdfObjectDictionary) error {
// TODO(dennwc): this code is too verbose; maybe use reflection to populate fields and validate afterwards?
R, ok := ed.Get("R").(*PdfObjectInteger)
if !ok {
return errors.New("encrypt dictionary missing R")
}
// TODO(dennwc): according to spec, R should be validated according to V value
if *R < 2 || *R > 6 {
return fmt.Errorf("invalid R (%d)", *R)
}
d.R = int(*R)
O, ok := ed.GetString("O")
if !ok {
return errors.New("encrypt dictionary missing O")
}
if d.R == 5 || d.R == 6 {
// the spec says =48 bytes, but Acrobat pads them out longer
if len(O) < 48 {
return fmt.Errorf("Length(O) < 48 (%d)", len(O))
}
} else if len(O) != 32 {
return fmt.Errorf("Length(O) != 32 (%d)", len(O))
}
d.O = []byte(O)
U, ok := ed.GetString("U")
if !ok {
return errors.New("encrypt dictionary missing U")
}
if d.R == 5 || d.R == 6 {
// the spec says =48 bytes, but Acrobat pads them out longer
if len(U) < 48 {
return fmt.Errorf("Length(U) < 48 (%d)", len(U))
}
} else if len(U) != 32 {
// Strictly this does not cause an error.
// If O is OK and others then can still read the file.
common.Log.Debug("Warning: Length(U) != 32 (%d)", len(U))
//return crypter, errors.New("Length(U) != 32")
}
d.U = []byte(U)
if d.R >= 5 {
OE, ok := ed.GetString("OE")
if !ok {
return errors.New("encrypt dictionary missing OE")
} else if len(OE) != 32 {
return fmt.Errorf("Length(OE) != 32 (%d)", len(OE))
}
d.OE = []byte(OE)
UE, ok := ed.GetString("UE")
if !ok {
return errors.New("encrypt dictionary missing UE")
} else if len(UE) != 32 {
return fmt.Errorf("Length(UE) != 32 (%d)", len(UE))
}
d.UE = []byte(UE)
}
P, ok := ed.Get("P").(*PdfObjectInteger)
if !ok {
return errors.New("encrypt dictionary missing permissions attr")
}
d.P = AccessPermissions(*P)
if d.R == 6 {
Perms, ok := ed.GetString("Perms")
if !ok {
return errors.New("encrypt dictionary missing Perms")
} else if len(Perms) != 16 {
return fmt.Errorf("Length(Perms) != 16 (%d)", len(Perms))
}
d.Perms = []byte(Perms)
}
if em, ok := ed.Get("EncryptMetadata").(*PdfObjectBool); ok {
d.EncryptMetadata = bool(*em)
} else {
d.EncryptMetadata = true // True by default.
}
return nil
}

View File

@ -11,6 +11,7 @@ import (
"testing"
"github.com/unidoc/unidoc/common"
"github.com/unidoc/unidoc/pdf/core/security"
)
func init() {
@ -24,7 +25,7 @@ func TestDecryption1(t *testing.T) {
V: 2,
Length: 128,
},
encryptStd: stdEncryptDict{
encryptStd: security.StdEncryptDict{
R: 3,
P: 0xfffff0c0,
EncryptMetadata: true,

View File

@ -18,6 +18,7 @@ import (
"strings"
"github.com/unidoc/unidoc/common"
"github.com/unidoc/unidoc/pdf/core/security"
)
// Regular Expressions for parsing and identifying object signatures.
@ -1641,11 +1642,11 @@ func (parser *PdfParser) Decrypt(password []byte) (bool, error) {
// The bool flag indicates that the user can access and 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.
func (parser *PdfParser) CheckAccessRights(password []byte) (bool, AccessPermissions, error) {
func (parser *PdfParser) CheckAccessRights(password []byte) (bool, security.Permissions, error) {
// Also build the encryption/decryption key.
if parser.crypter == nil {
// If the crypter is not set, the file is not encrypted and we can assume full access permissions.
return true, PermOwner, nil
return true, security.PermOwner, nil
}
return parser.crypter.checkAccessRights(password)
}

View File

@ -3,7 +3,7 @@
* file 'LICENSE.md', which is part of this source code package.
*/
package core
package security
import "crypto/cipher"

View File

@ -0,0 +1,32 @@
/*
* This file is subject to the terms and conditions defined in
* file 'LICENSE.md', which is part of this source code package.
*/
package security
// StdHandler is an interface for standard security handlers.
type StdHandler interface {
// GenerateParams uses owner and user passwords to set encryption parameters and generate an encryption key.
// It assumes that R, P and EncryptMetadata are already set.
GenerateParams(d *StdEncryptDict, ownerPass, userPass []byte) ([]byte, error)
// Authenticate uses encryption dictionary parameters and the password to calculate
// the document encryption key. It also returns permissions that should be granted to a user.
// In case of failed authentication, it returns empty key and zero permissions with no error.
Authenticate(d *StdEncryptDict, pass []byte) ([]byte, Permissions, error)
}
// 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.
P Permissions
EncryptMetadata bool // Indicates whether the document-level metadata stream shall be encrypted.
// set by security handlers:
O, U []byte
OE, UE []byte // R=6
Perms []byte // An encrypted copy of P (16 bytes). Used to verify permissions. R=6
}

View File

@ -0,0 +1,28 @@
package security
import "math"
// Permissions is a bitmask of access permissions for a PDF file.
type Permissions uint32
const (
// PermOwner grants all permissions.
PermOwner = Permissions(math.MaxUint32)
PermPrinting = Permissions(1 << 2) // bit 3
PermModify = Permissions(1 << 3) // bit 4
PermExtractGraphics = Permissions(1 << 4) // bit 5
PermAnnotate = Permissions(1 << 5) // bit 6
// PermFillForms allow form filling, if annotation is disabled? If annotation enabled, is not looked at.
PermFillForms = Permissions(1 << 8) // bit 9
PermDisabilityExtract = Permissions(1 << 9) // bit 10 // TODO: not clear what this means!
// PermRotateInsert allows rotating, editing page order.
PermRotateInsert = Permissions(1 << 10) // bit 11
// PermFullPrintQuality limits print quality (lowres), assuming Printing bit is set.
PermFullPrintQuality = Permissions(1 << 11) // bit 12
)
// Allowed checks if a set of permissions can be granted.
func (p Permissions) Allowed(p2 Permissions) bool {
return p&p2 == p2
}

View File

@ -3,7 +3,7 @@
* file 'LICENSE.md', which is part of this source code package.
*/
package core
package security
import (
"bytes"
@ -15,7 +15,16 @@ import (
"github.com/unidoc/unidoc/common"
)
var _ stdSecurityHandler = stdHandlerR4{}
var _ StdHandler = stdHandlerR4{}
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"
// NewHandlerR4 creates a new standard security handler for R<=4.
func NewHandlerR4(id0 string, length int) StdHandler {
return stdHandlerR4{ID0: id0, Length: length}
}
type stdHandlerR4 struct {
Length int
@ -40,7 +49,7 @@ func (sh stdHandlerR4) paddedPass(pass []byte) []byte {
}
// alg2 computes an encryption key.
func (sh stdHandlerR4) alg2(d *stdEncryptDict, pass []byte) []byte {
func (sh stdHandlerR4) alg2(d *StdEncryptDict, pass []byte) []byte {
common.Log.Trace("alg2")
key := sh.paddedPass(pass)
@ -212,7 +221,7 @@ func (sh stdHandlerR4) alg5(ekey []byte, upass []byte) ([]byte, error) {
// alg6 authenticates the user password and returns the document encryption key.
// It returns an nil key in case authentication failed.
func (sh stdHandlerR4) alg6(d *stdEncryptDict, upass []byte) ([]byte, error) {
func (sh stdHandlerR4) alg6(d *StdEncryptDict, upass []byte) ([]byte, error) {
var (
uo []byte
err error
@ -252,7 +261,7 @@ func (sh stdHandlerR4) alg6(d *stdEncryptDict, upass []byte) ([]byte, error) {
// alg7 authenticates the owner password and returns the document encryption key.
//// It returns an nil key in case authentication failed.
func (sh stdHandlerR4) alg7(d *stdEncryptDict, opass []byte) ([]byte, error) {
func (sh stdHandlerR4) alg7(d *StdEncryptDict, opass []byte) ([]byte, error) {
encKey := sh.alg3Key(d.R, opass)
decrypted := make([]byte, len(d.O))
@ -289,7 +298,7 @@ func (sh stdHandlerR4) alg7(d *stdEncryptDict, opass []byte) ([]byte, error) {
return ekey, nil
}
func (sh stdHandlerR4) GenerateParams(d *stdEncryptDict, opass, upass []byte) ([]byte, error) {
func (sh stdHandlerR4) GenerateParams(d *StdEncryptDict, opass, upass []byte) ([]byte, error) {
// Make the O and U objects.
O, err := sh.alg3(d.R, upass, opass)
if err != nil {
@ -311,7 +320,7 @@ func (sh stdHandlerR4) GenerateParams(d *stdEncryptDict, opass, upass []byte) ([
return ekey, nil
}
func (sh stdHandlerR4) Authenticate(d *stdEncryptDict, pass []byte) ([]byte, AccessPermissions, error) {
func (sh stdHandlerR4) Authenticate(d *StdEncryptDict, pass []byte) ([]byte, Permissions, error) {
// Try owner password.
// May not be necessary if only want to get all contents.
// (user pass needs to be known or empty).

View File

@ -3,7 +3,7 @@
* file 'LICENSE.md', which is part of this source code package.
*/
package core
package security
import (
"github.com/unidoc/unidoc/common"
@ -53,7 +53,7 @@ func TestAlg2(t *testing.T) {
0xff, 0xd5, 0x82, 0xe4, 0xec, 0x0e, 0xa3, 0xb4}),
Length: 128,
}
d := &stdEncryptDict{
d := &StdEncryptDict{
R: 3,
P: 0xfffff0c0,
EncryptMetadata: true,
@ -110,7 +110,7 @@ func TestAlg5(t *testing.T) {
0xff, 0xd5, 0x82, 0xe4, 0xec, 0x0e, 0xa3, 0xb4}),
Length: 128,
}
d := &stdEncryptDict{
d := &StdEncryptDict{
R: 3,
P: 0xfffff0c0,
EncryptMetadata: true,

View File

@ -3,7 +3,7 @@
* file 'LICENSE.md', which is part of this source code package.
*/
package core
package security
import (
"bytes"
@ -19,13 +19,19 @@ import (
"math"
)
var _ stdSecurityHandler = stdHandlerR6{}
var _ StdHandler = stdHandlerR6{}
// NewHandlerR6 creates a new standard security handler for R=5 and R=6.
func NewHandlerR6() StdHandler {
return stdHandlerR6{}
}
// stdHandlerR6 is an implementation of standard security handler with R=5 and R=6.
type stdHandlerR6 struct{}
// alg2a retrieves the encryption key from an encrypted document (R >= 5).
// 7.6.4.3.2 Algorithm 2.A (page 83)
func (sh stdHandlerR6) alg2a(d *stdEncryptDict, pass []byte) ([]byte, AccessPermissions, error) {
func (sh stdHandlerR6) alg2a(d *StdEncryptDict, pass []byte) ([]byte, Permissions, error) {
// O & U: 32 byte hash + 8 byte Validation Salt + 8 byte Key Salt
// step a: Unicode normalization
@ -46,7 +52,7 @@ func (sh stdHandlerR6) alg2a(d *stdEncryptDict, pass []byte) ([]byte, AccessPerm
ekey []byte // encrypted file key
ukey []byte // user key; set only when using owner's password
)
var perm AccessPermissions
var perm Permissions
if len(h) != 0 {
// owner password valid
perm = PermOwner
@ -217,7 +223,7 @@ func (sh stdHandlerR6) alg2b(R int, data, pwd, userKey []byte) []byte {
// 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 (sh stdHandlerR6) alg8(d *stdEncryptDict, ekey []byte, upass []byte) error {
func (sh stdHandlerR6) alg8(d *StdEncryptDict, ekey []byte, upass []byte) error {
// step a: compute U (user password)
var rbuf [16]byte
if _, err := io.ReadFull(rand.Reader, rbuf[:]); err != nil {
@ -263,7 +269,7 @@ func (sh stdHandlerR6) alg8(d *stdEncryptDict, ekey []byte, upass []byte) error
// 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 (sh stdHandlerR6) alg9(d *stdEncryptDict, ekey []byte, opass []byte) error {
func (sh stdHandlerR6) alg9(d *StdEncryptDict, ekey []byte, opass []byte) error {
// step a: compute O (owner password)
var rbuf [16]byte
if _, err := io.ReadFull(rand.Reader, rbuf[:]); err != nil {
@ -312,7 +318,7 @@ func (sh stdHandlerR6) alg9(d *stdEncryptDict, ekey []byte, opass []byte) error
// alg10 computes the encryption dictionary's Perms (permissions) value (R=6).
// 7.6.4.4.8 Algorithm 10 (page 87)
func (sh stdHandlerR6) alg10(d *stdEncryptDict, ekey []byte) error {
func (sh stdHandlerR6) alg10(d *StdEncryptDict, ekey []byte) error {
// step a: extend permissions to 64 bits
perms := uint64(uint32(d.P)) | (math.MaxUint32 << 32)
@ -352,7 +358,7 @@ func (sh stdHandlerR6) alg10(d *stdEncryptDict, ekey []byte) error {
}
// alg11 authenticates the user password (R >= 5) and returns the hash.
func (sh stdHandlerR6) alg11(d *stdEncryptDict, upass []byte) ([]byte, error) {
func (sh stdHandlerR6) alg11(d *StdEncryptDict, upass []byte) ([]byte, error) {
str := make([]byte, len(upass)+8)
i := copy(str, upass)
i += copy(str[i:], d.U[32:40]) // user Validation Salt
@ -367,7 +373,7 @@ func (sh stdHandlerR6) alg11(d *stdEncryptDict, 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 (sh stdHandlerR6) alg12(d *stdEncryptDict, opass []byte) ([]byte, error) {
func (sh stdHandlerR6) alg12(d *StdEncryptDict, opass []byte) ([]byte, error) {
str := make([]byte, len(opass)+8+48)
i := copy(str, opass)
i += copy(str[i:], d.O[32:40]) // owner Validation Salt
@ -383,7 +389,7 @@ func (sh stdHandlerR6) alg12(d *stdEncryptDict, 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 (sh stdHandlerR6) alg13(d *stdEncryptDict, fkey []byte) error {
func (sh stdHandlerR6) alg13(d *StdEncryptDict, fkey []byte) error {
perms := make([]byte, 16)
copy(perms, d.Perms[:16])
@ -398,7 +404,7 @@ func (sh stdHandlerR6) alg13(d *stdEncryptDict, fkey []byte) error {
if !bytes.Equal(perms[9:12], []byte("adb")) {
return errors.New("decoded permissions are invalid")
}
p := AccessPermissions(binary.LittleEndian.Uint32(perms[0:4]))
p := Permissions(binary.LittleEndian.Uint32(perms[0:4]))
if p != d.P {
return errors.New("permissions validation failed")
}
@ -419,7 +425,7 @@ func (sh stdHandlerR6) alg13(d *stdEncryptDict, fkey []byte) error {
// generateR6 is the algorithm opposite to alg2a (R>=5).
// It generates U,O,UE,OE,Perms fields using AESv3 encryption.
// There is no algorithm number assigned to this function in the spec.
func (sh stdHandlerR6) GenerateParams(d *stdEncryptDict, opass, upass []byte) ([]byte, error) {
func (sh stdHandlerR6) GenerateParams(d *StdEncryptDict, opass, upass []byte) ([]byte, error) {
ekey := make([]byte, 32)
if _, err := io.ReadFull(rand.Reader, ekey); err != nil {
return nil, err
@ -455,6 +461,6 @@ func (sh stdHandlerR6) GenerateParams(d *stdEncryptDict, opass, upass []byte) ([
return ekey, nil
}
func (sh stdHandlerR6) Authenticate(d *stdEncryptDict, pass []byte) ([]byte, AccessPermissions, error) {
func (sh stdHandlerR6) Authenticate(d *StdEncryptDict, pass []byte) ([]byte, Permissions, error) {
return sh.alg2a(d, pass)
}

View File

@ -1,4 +1,4 @@
package core
package security
import (
"bytes"
@ -60,7 +60,7 @@ func TestStdHandlerR6(t *testing.T) {
c := c
t.Run(c.Name, func(t *testing.T) {
sh := stdHandlerR6{} // V=5
d := &stdEncryptDict{
d := &StdEncryptDict{
R: R, P: perms,
EncryptMetadata: c.EncMeta,
}

View File

@ -13,6 +13,7 @@ import (
"github.com/unidoc/unidoc/common"
. "github.com/unidoc/unidoc/pdf/core"
"github.com/unidoc/unidoc/pdf/core/security"
)
// PdfReader represents a PDF file reader. It is a frontend to the lower level parsing mechanism and provides
@ -110,7 +111,7 @@ func (this *PdfReader) Decrypt(password []byte) (bool, error) {
// The bool flag indicates that the user can access and 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.
func (this *PdfReader) CheckAccessRights(password []byte) (bool, AccessPermissions, error) {
func (this *PdfReader) CheckAccessRights(password []byte) (bool, security.Permissions, error) {
return this.parser.CheckAccessRights(password)
}

View File

@ -20,6 +20,7 @@ import (
"github.com/unidoc/unidoc/common"
"github.com/unidoc/unidoc/common/license"
. "github.com/unidoc/unidoc/pdf/core"
"github.com/unidoc/unidoc/pdf/core/security"
"github.com/unidoc/unidoc/pdf/model/fonts"
)
@ -648,7 +649,7 @@ func (this *PdfWriter) updateObjectNumbers() {
// EncryptOptions represents encryption options for an output PDF.
type EncryptOptions struct {
Permissions AccessPermissions
Permissions security.Permissions
Algorithm EncryptionAlgorithm
}
@ -670,7 +671,7 @@ func (this *PdfWriter) Encrypt(userPass, ownerPass []byte, options *EncryptOptio
if options != nil {
algo = options.Algorithm
}
perm := PermOwner
perm := security.PermOwner
if options != nil {
perm = options.Permissions
}