mirror of
https://github.com/unidoc/unipdf.git
synced 2025-05-02 22:17:06 +08:00
Merge branch 'v3' into fonts_minor_2
This commit is contained in:
commit
04e74d73f6
@ -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)
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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)
|
||||
|
Loading…
x
Reference in New Issue
Block a user