diff --git a/pdf/core/security/handlers.go b/pdf/core/security/handlers.go index a72e6f2f..48857fb4 100644 --- a/pdf/core/security/handlers.go +++ b/pdf/core/security/handlers.go @@ -5,6 +5,8 @@ package security +import "fmt" + // 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. @@ -30,3 +32,22 @@ type StdEncryptDict struct { OE, UE []byte // R=6 Perms []byte // An encrypted copy of P (16 bytes). Used to verify permissions. R=6 } + +// checkAtLeast checks the size of the bytes field and returns a descriptive error if it doesn't. +func checkAtLeast(fnc, field string, exp int, b []byte) error { + if len(b) < exp { + return errInvalidField{Func: fnc, Field: field, Exp: exp, Got: len(b)} + } + return nil +} + +type errInvalidField struct { + Func string + Field string + Exp int + Got int +} + +func (e errInvalidField) Error() string { + return fmt.Sprintf("%s: expected %s field to be %d bytes, got %d", e.Func, e.Field, e.Exp, e.Got) +} diff --git a/pdf/core/security/standard_r4.go b/pdf/core/security/standard_r4.go index c4d655c6..9efc18bf 100644 --- a/pdf/core/security/standard_r4.go +++ b/pdf/core/security/standard_r4.go @@ -10,6 +10,7 @@ import ( "crypto/md5" "crypto/rand" "crypto/rc4" + "encoding/binary" "errors" "github.com/unidoc/unidoc/common" @@ -35,19 +36,11 @@ type stdHandlerR4 struct { ID0 string } -func (sh stdHandlerR4) paddedPass(pass []byte) []byte { +func (stdHandlerR4) paddedPass(pass []byte) []byte { 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)] - } + i := copy(key, pass) + for ; i < 32; i++ { + key[i] = padding[i-len(pass)] } return key } @@ -64,12 +57,9 @@ func (sh stdHandlerR4) alg2(d *StdEncryptDict, pass []byte) []byte { h.Write(d.O) // Pass P (Lower order byte first). - var p = uint32(d.P) - var pb []byte - for i := 0; i < 4; i++ { - pb = append(pb, byte(((p >> uint(8*i)) & 0xff))) - } - h.Write(pb) + var pb [4]byte + binary.LittleEndian.PutUint32(pb[:], uint32(d.P)) + h.Write(pb[:]) common.Log.Trace("go P: % x", pb) // Pass ID[0] from the trailer @@ -82,8 +72,9 @@ func (sh stdHandlerR4) alg2(d *StdEncryptDict, pass []byte) []byte { hashb := h.Sum(nil) if d.R >= 3 { + h = md5.New() for i := 0; i < 50; i++ { - h = md5.New() + h.Reset() h.Write(hashb[0 : sh.Length/8]) hashb = h.Sum(nil) } diff --git a/pdf/core/security/standard_r6.go b/pdf/core/security/standard_r6.go index 3ead14c9..3becf56c 100644 --- a/pdf/core/security/standard_r6.go +++ b/pdf/core/security/standard_r6.go @@ -21,6 +21,16 @@ import ( var _ StdHandler = stdHandlerR6{} +// newAESCipher creates a new AES block cipher. +// The size of a buffer should be exactly 16, 24 or 32 bytes, in other cases the function will panic. +func newAESCipher(b []byte) cipher.Block { + c, err := aes.NewCipher(b) + if err != nil { + panic(err) + } + return c +} + // NewHandlerR6 creates a new standard security handler for R=5 and R=6. func NewHandlerR6() StdHandler { return stdHandlerR6{} @@ -34,6 +44,12 @@ type stdHandlerR6 struct{} // 7.6.4.3.2 Algorithm 2.A (page 83) func (sh stdHandlerR6) alg2a(d *StdEncryptDict, pass []byte) ([]byte, Permissions, error) { // O & U: 32 byte hash + 8 byte Validation Salt + 8 byte Key Salt + if err := checkAtLeast("alg2a", "O", 48, d.O); err != nil { + return nil, 0, err + } + if err := checkAtLeast("alg2a", "U", 48, d.U); err != nil { + return nil, 0, err + } // step a: Unicode normalization // TODO(dennwc): make sure that UTF-8 strings are normalized @@ -90,6 +106,9 @@ func (sh stdHandlerR6) alg2a(d *StdEncryptDict, pass []byte) ([]byte, Permission ekey = d.UE ukey = nil } + if err := checkAtLeast("alg2a", "Key", 32, ekey); err != nil { + return nil, 0, err + } ekey = ekey[:32] // intermediate key @@ -164,10 +183,7 @@ func alg2b(data, pwd, userKey []byte) []byte { repeat(K1, n) // step b: encrypt K1 with AES-128 CBC - ac, err := aes.NewCipher(K[0:16]) - if err != nil { - panic(err) - } + ac := newAESCipher(K[0:16]) cbc := cipher.NewCBCEncrypter(ac, K[16:32]) cbc.CryptBlocks(K1, K1) E = K1 @@ -225,6 +241,9 @@ 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 { + if err := checkAtLeast("alg8", "Key", 32, ekey); err != nil { + return err + } // step a: compute U (user password) var rbuf [16]byte if _, err := io.ReadFull(rand.Reader, rbuf[:]); err != nil { @@ -254,10 +273,7 @@ func (sh stdHandlerR6) alg8(d *StdEncryptDict, ekey []byte, upass []byte) error h = sh.alg2b(d.R, str, upass, nil) - ac, err := aes.NewCipher(h[:32]) - if err != nil { - panic(err) - } + ac := newAESCipher(h[:32]) iv := make([]byte, aes.BlockSize) cbc := cipher.NewCBCEncrypter(ac, iv) @@ -271,6 +287,12 @@ 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 { + if err := checkAtLeast("alg9", "Key", 32, ekey); err != nil { + return err + } + if err := checkAtLeast("alg9", "U", 48, d.U); err != nil { + return err + } // step a: compute O (owner password) var rbuf [16]byte if _, err := io.ReadFull(rand.Reader, rbuf[:]); err != nil { @@ -303,10 +325,7 @@ func (sh stdHandlerR6) alg9(d *StdEncryptDict, ekey []byte, opass []byte) error h = sh.alg2b(d.R, str, opass, userKey) - ac, err := aes.NewCipher(h[:32]) - if err != nil { - panic(err) - } + ac := newAESCipher(h[:32]) iv := make([]byte, aes.BlockSize) cbc := cipher.NewCBCEncrypter(ac, iv) @@ -320,6 +339,9 @@ 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 { + if err := checkAtLeast("alg10", "Key", 32, ekey); err != nil { + return err + } // step a: extend permissions to 64 bits perms := uint64(uint32(d.P)) | (math.MaxUint32 << 32) @@ -346,10 +368,7 @@ func (sh stdHandlerR6) alg10(d *StdEncryptDict, ekey []byte) error { } // step f: encrypt permissions - ac, err := aes.NewCipher(ekey[:32]) - if err != nil { - panic(err) - } + ac := newAESCipher(ekey[:32]) ecb := newECBEncrypter(ac) ecb.CryptBlocks(Perms, Perms) @@ -360,6 +379,9 @@ 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) { + if err := checkAtLeast("alg11", "U", 48, d.U); err != nil { + return nil, err + } str := make([]byte, len(upass)+8) i := copy(str, upass) i += copy(str[i:], d.U[32:40]) // user Validation Salt @@ -375,6 +397,12 @@ 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) { + if err := checkAtLeast("alg12", "U", 48, d.U); err != nil { + return nil, err + } + if err := checkAtLeast("alg12", "O", 48, d.O); err != nil { + return nil, err + } str := make([]byte, len(opass)+8+48) i := copy(str, opass) i += copy(str[i:], d.O[32:40]) // owner Validation Salt @@ -391,12 +419,18 @@ 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 { + if err := checkAtLeast("alg13", "Key", 32, fkey); err != nil { + return err + } + if err := checkAtLeast("alg13", "Perms", 16, d.Perms); err != nil { + return err + } perms := make([]byte, 16) copy(perms, d.Perms[:16]) ac, err := aes.NewCipher(fkey[:32]) if err != nil { - panic(err) + return err } ecb := newECBDecrypter(ac)