security: add missing license headers, more documentation

This commit is contained in:
Denys Smirnov 2018-10-08 01:04:56 +03:00
parent 7bd4ba688d
commit 84284c88ec
11 changed files with 123 additions and 42 deletions

View File

@ -17,14 +17,20 @@ import (
crypto "github.com/unidoc/unidoc/pdf/core/security/crypt"
)
// Version represents a version of a PDF standard.
type Version struct {
Major int
Minor int
}
// EncryptInfo contains an information generated by the document encrypter.
type EncryptInfo struct {
// Version is minimal PDF version that supports specified encryption algorithm.
Version
Encrypt *PdfObjectDictionary
// Encrypt is an encryption dictionary that contains all necessary parameters.
// It should be stored in all copies of the document trailer.
Encrypt *PdfObjectDictionary
// ID0 and ID1 are IDs used in the trailer. Older algorithms such as RC4 uses them for encryption.
ID0, ID1 string
}
@ -57,7 +63,7 @@ func PdfCryptNewEncrypt(cf crypto.Filter, userPass, ownerPass []byte, perm secur
crypter.streamFilter = defaultFilter
crypter.stringFilter = defaultFilter
}
ed := crypter.newEncyptDict()
ed := crypter.newEncryptDict()
// Prepare the ID object for the trailer.
hashcode := md5.Sum([]byte(time.Now().Format(time.RFC850)))
@ -244,7 +250,7 @@ func decodeCryptFilter(cf *crypto.FilterDict, d *PdfObjectDictionary) error {
return nil
}
func (crypt *PdfCrypt) newEncyptDict() *PdfObjectDictionary {
func (crypt *PdfCrypt) newEncryptDict() *PdfObjectDictionary {
// Generate the encryption dictionary.
ed := MakeDict()
ed.Set("Filter", MakeName("Standard"))

View File

@ -1,9 +1,16 @@
/*
* This file is subject to the terms and conditions defined in
* file 'LICENSE.md', which is part of this source code package.
*/
package security
// AuthEvent is an event type that triggers authentication.
type AuthEvent string
const (
EventDocOpen = AuthEvent("DocOpen") // document open
EventEFOpen = AuthEvent("EFOpen") // embedded file open
// EventDocOpen is an event triggered when opening the document.
EventDocOpen = AuthEvent("DocOpen")
// EventEFOpen is an event triggered when accessing an embedded file.
EventEFOpen = AuthEvent("EFOpen")
)

View File

@ -1,3 +1,8 @@
/*
* This file is subject to the terms and conditions defined in
* file 'LICENSE.md', which is part of this source code package.
*/
package crypt
import "fmt"
@ -22,28 +27,35 @@ func newFilterAESV2(d FilterDict) (Filter, error) {
return filterAESV2{}, nil
}
var _ Filter = filterAESV2{}
// filterAESV2 is an AES-based filter (128 bit key, PDF 1.6)
type filterAESV2 struct {
filterAES
}
// PDFVersion implements Filter interface.
func (filterAESV2) PDFVersion() [2]int {
return [2]int{1, 5}
}
// HandlerVersion implements Filter interface.
func (filterAESV2) HandlerVersion() (V, R int) {
V, R = 4, 4
return
}
// Name implements Filter interface.
func (filterAESV2) Name() string {
return "AESV2"
}
// KeyLength implements Filter interface.
func (filterAESV2) KeyLength() int {
return 128 / 8
}
// MakeKey implements Filter interface.
func (filterAESV2) MakeKey(objNum, genNum uint32, ekey []byte) ([]byte, error) {
return makeKeyV2(objNum, genNum, ekey, true)
}

View File

@ -1,3 +1,8 @@
/*
* This file is subject to the terms and conditions defined in
* file 'LICENSE.md', which is part of this source code package.
*/
package crypt
import (
@ -146,28 +151,35 @@ func (filterAES) DecryptBytes(buf []byte, okey []byte) ([]byte, error) {
return buf, nil
}
var _ Filter = filterAESV3{}
// filterAESV3 is an AES-based filter (256 bit key, PDF 2.0)
type filterAESV3 struct {
filterAES
}
// PDFVersion implements Filter interface.
func (filterAESV3) PDFVersion() [2]int {
return [2]int{2, 0}
}
// HandlerVersion implements Filter interface.
func (filterAESV3) HandlerVersion() (V, R int) {
V, R = 5, 6
return
}
// Name implements Filter interface.
func (filterAESV3) Name() string {
return "AESV3"
}
// KeyLength implements Filter interface.
func (filterAESV3) KeyLength() int {
return 256 / 8
}
// MakeKey implements Filter interface.
func (filterAESV3) MakeKey(_, _ uint32, ekey []byte) ([]byte, error) {
return ekey, nil
return ekey, nil // document encryption key == object encryption key
}

View File

@ -1,3 +1,8 @@
/*
* This file is subject to the terms and conditions defined in
* file 'LICENSE.md', which is part of this source code package.
*/
package crypt
import (
@ -21,6 +26,7 @@ func NewFilterV2(length int) Filter {
return f
}
// newFilterV2 creates a RC4-based filter from a Filter dictionary.
func newFilterV2(d FilterDict) (Filter, error) {
if d.Length%8 != 0 {
return nil, fmt.Errorf("Crypt filter length not multiple of 8 (%d)", d.Length)
@ -74,32 +80,40 @@ func makeKeyV2(objNum, genNum uint32, ekey []byte, isAES bool) ([]byte, error) {
return hashb, nil
}
var _ Filter = filterV2{}
// filterV2 is a RC4-based filter
type filterV2 struct {
length int
}
// PDFVersion implements Filter interface.
func (f filterV2) PDFVersion() [2]int {
return [2]int{} // TODO(dennwc): unspecified; check what it should be
}
// HandlerVersion implements Filter interface.
func (f filterV2) HandlerVersion() (V, R int) {
V, R = 2, 3
return
}
// Name implements Filter interface.
func (filterV2) Name() string {
return "V2"
}
// KeyLength implements Filter interface.
func (f filterV2) KeyLength() int {
return f.length
}
// MakeKey implements Filter interface.
func (f filterV2) MakeKey(objNum, genNum uint32, ekey []byte) ([]byte, error) {
return makeKeyV2(objNum, genNum, ekey, false)
}
// EncryptBytes implements Filter interface.
func (filterV2) EncryptBytes(buf []byte, okey []byte) ([]byte, error) {
// Standard RC4 algorithm.
ciph, err := rc4.NewCipher(okey)
@ -112,6 +126,7 @@ func (filterV2) EncryptBytes(buf []byte, okey []byte) ([]byte, error) {
return buf, nil
}
// DecryptBytes implements Filter interface.
func (filterV2) DecryptBytes(buf []byte, okey []byte) ([]byte, error) {
// Standard RC4 algorithm.
ciph, err := rc4.NewCipher(okey)

View File

@ -1,3 +1,8 @@
/*
* This file is subject to the terms and conditions defined in
* file 'LICENSE.md', which is part of this source code package.
*/
package crypt
import (
@ -13,6 +18,27 @@ var (
// filterFunc is used to construct crypt filters from CryptFilter dictionary
type filterFunc func(d FilterDict) (Filter, error)
// Filter is a common interface for crypt filter methods.
type Filter interface {
// Name returns a name of the filter that should be used in CFM field of Encrypt dictionary.
Name() string
// KeyLength returns a length of the encryption key in bytes.
KeyLength() int
// PDFVersion reports the minimal version of PDF document that introduced this filter.
PDFVersion() [2]int
// HandlerVersion reports V and R parameters that should be used for this filter.
HandlerVersion() (V, R int)
// MakeKey generates a object encryption key based on file encryption key and object numbers.
// Used only for legacy filters - AESV3 doesn't change the key for each object.
MakeKey(objNum, genNum uint32, fkey []byte) ([]byte, error)
// EncryptBytes encrypts a buffer using object encryption key, as returned by MakeKey.
// Implementation may reuse a buffer and encrypt data in-place.
EncryptBytes(p []byte, okey []byte) ([]byte, error)
// DecryptBytes decrypts a buffer using object encryption key, as returned by MakeKey.
// Implementation may reuse a buffer and decrypt data in-place.
DecryptBytes(p []byte, okey []byte) ([]byte, error)
}
// NewFilter creates CryptFilter from a corresponding dictionary.
func NewFilter(d FilterDict) (Filter, error) {
fnc, err := getFilter(d.CFM)
@ -56,27 +82,6 @@ func getFilter(name string) (filterFunc, error) {
return f, nil
}
// Filter is a common interface for crypt filter methods.
type Filter interface {
// Name returns a name of the filter that should be used in CFM field of Encrypt dictionary.
Name() string
// KeyLength returns a length of the encryption key in bytes.
KeyLength() int
// PDFVersion reports the minimal version of PDF document that introduced this filter.
PDFVersion() [2]int
// HandlerVersion reports V and R parameters that should be used for this filter.
HandlerVersion() (V, R int)
// MakeKey generates a object encryption key based on file encryption key and object numbers.
// Used only for legacy filters - AESV3 doesn't change the key for each object.
MakeKey(objNum, genNum uint32, fkey []byte) ([]byte, error)
// EncryptBytes encrypts a buffer using object encryption key, as returned by MakeKey.
// Implementation may reuse a buffer and encrypt data in-place.
EncryptBytes(p []byte, okey []byte) ([]byte, error)
// DecryptBytes decrypts a buffer using object encryption key, as returned by MakeKey.
// Implementation may reuse a buffer and decrypt data in-place.
DecryptBytes(p []byte, okey []byte) ([]byte, error)
}
type filterIdentity struct{}
func (filterIdentity) PDFVersion() [2]int {

View File

@ -1,3 +1,8 @@
/*
* This file is subject to the terms and conditions defined in
* file 'LICENSE.md', which is part of this source code package.
*/
package security
import "math"
@ -9,17 +14,22 @@ 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
// PermPrinting allows printing the document with a low quality.
PermPrinting = Permissions(1 << 2)
// PermModify allows to modify the document.
PermModify = Permissions(1 << 3)
// PermExtractGraphics allows to extract graphics from the document.
PermExtractGraphics = Permissions(1 << 4)
// PermAnnotate allows annotating the document.
PermAnnotate = Permissions(1 << 5)
// 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!
PermFillForms = Permissions(1 << 8)
// PermDisabilityExtract allows to extract graphics in accessibility mode.
PermDisabilityExtract = Permissions(1 << 9)
// PermRotateInsert allows rotating, editing page order.
PermRotateInsert = Permissions(1 << 10) // bit 11
PermRotateInsert = Permissions(1 << 10)
// PermFullPrintQuality limits print quality (lowres), assuming Printing bit is set.
PermFullPrintQuality = Permissions(1 << 11) // bit 12
PermFullPrintQuality = Permissions(1 << 11)
)
// Allowed checks if a set of permissions can be granted.

View File

@ -26,6 +26,10 @@ func NewHandlerR4(id0 string, length int) StdHandler {
return stdHandlerR4{ID0: id0, Length: length}
}
// stdHandlerR4 is a standard security handler for R<=4.
// It uses RC4 and MD5 to generate encryption parameters.
// This legacy handler also requires Length parameter from
// Encrypt dictionary and ID0 from the trailer.
type stdHandlerR4 struct {
Length int
ID0 string
@ -260,7 +264,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.
// It returns an nil key in case authentication failed.
func (sh stdHandlerR4) alg7(d *StdEncryptDict, opass []byte) ([]byte, error) {
encKey := sh.alg3Key(d.R, opass)
@ -298,6 +302,8 @@ func (sh stdHandlerR4) alg7(d *StdEncryptDict, opass []byte) ([]byte, error) {
return ekey, nil
}
// GenerateParams generates and sets O and U parameters for the encryption dictionary.
// It expects R, P and EncryptMetadata fields to be set.
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)
@ -320,6 +326,7 @@ func (sh stdHandlerR4) GenerateParams(d *StdEncryptDict, opass, upass []byte) ([
return ekey, nil
}
// Authenticate implements StdHandler interface.
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.

View File

@ -27,6 +27,7 @@ func NewHandlerR6() StdHandler {
}
// stdHandlerR6 is an implementation of standard security handler with R=5 and R=6.
// Both revisions are expected to be used with AES encryption filters.
type stdHandlerR6 struct{}
// alg2a retrieves the encryption key from an encrypted document (R >= 5).
@ -115,10 +116,10 @@ func (sh stdHandlerR6) alg2a(d *StdEncryptDict, pass []byte) ([]byte, Permission
return fkey, perm, nil
}
// alg2b_R5 computes a hash for R=5, used in a deprecated extension.
// alg2bR5 computes a hash for R=5, used in a deprecated extension.
// It's used the same way as a hash described in Algorithm 2.B, but it doesn't use the original password
// and the user key to calculate the hash.
func alg2b_R5(data []byte) []byte {
func alg2bR5(data []byte) []byte {
h := sha256.New()
h.Write(data)
return h.Sum(nil)
@ -216,7 +217,7 @@ func alg2b(data, pwd, userKey []byte) []byte {
// alg2b computes a hash for R=5 and R=6.
func (sh stdHandlerR6) alg2b(R int, data, pwd, userKey []byte) []byte {
if R == 5 {
return alg2b_R5(data)
return alg2bR5(data)
}
return alg2b(data, pwd, userKey)
}
@ -422,9 +423,10 @@ func (sh stdHandlerR6) alg13(d *StdEncryptDict, fkey []byte) error {
return nil
}
// generateR6 is the algorithm opposite to alg2a (R>=5).
// GenerateParams 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.
// It expects R, P and EncryptMetadata fields to be set.
func (sh stdHandlerR6) GenerateParams(d *StdEncryptDict, opass, upass []byte) ([]byte, error) {
ekey := make([]byte, 32)
if _, err := io.ReadFull(rand.Reader, ekey); err != nil {
@ -461,6 +463,7 @@ func (sh stdHandlerR6) GenerateParams(d *StdEncryptDict, opass, upass []byte) ([
return ekey, nil
}
// Authenticate implements StdHandler interface.
func (sh stdHandlerR6) Authenticate(d *StdEncryptDict, pass []byte) ([]byte, Permissions, error) {
return sh.alg2a(d, pass)
}

View File

@ -1,3 +1,8 @@
/*
* This file is subject to the terms and conditions defined in
* file 'LICENSE.md', which is part of this source code package.
*/
package security
import (

View File

@ -17,12 +17,11 @@ import (
"io"
"strings"
"github.com/unidoc/unidoc/pdf/core/security/crypt"
"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/core/security/crypt"
"github.com/unidoc/unidoc/pdf/model/fonts"
)