mirror of
https://github.com/unidoc/unipdf.git
synced 2025-05-02 22:17:06 +08:00
security: add missing license headers, more documentation
This commit is contained in:
parent
7bd4ba688d
commit
84284c88ec
@ -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"))
|
||||
|
@ -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")
|
||||
)
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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 {
|
||||
|
@ -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.
|
||||
|
@ -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.
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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 (
|
||||
|
@ -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"
|
||||
)
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user