mirror of
https://github.com/unidoc/unipdf.git
synced 2025-05-05 19:30:30 +08:00
Merge branch 'v3' into fonts_minor_2
This commit is contained in:
commit
04e74d73f6
@ -5,6 +5,8 @@
|
|||||||
|
|
||||||
package security
|
package security
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
// StdHandler is an interface for standard security handlers.
|
// StdHandler is an interface for standard security handlers.
|
||||||
type StdHandler interface {
|
type StdHandler interface {
|
||||||
// GenerateParams uses owner and user passwords to set encryption parameters and generate an encryption key.
|
// 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
|
OE, UE []byte // R=6
|
||||||
Perms []byte // An encrypted copy of P (16 bytes). Used to verify permissions. 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/md5"
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"crypto/rc4"
|
"crypto/rc4"
|
||||||
|
"encoding/binary"
|
||||||
"errors"
|
"errors"
|
||||||
|
|
||||||
"github.com/unidoc/unidoc/common"
|
"github.com/unidoc/unidoc/common"
|
||||||
@ -35,19 +36,11 @@ type stdHandlerR4 struct {
|
|||||||
ID0 string
|
ID0 string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sh stdHandlerR4) paddedPass(pass []byte) []byte {
|
func (stdHandlerR4) paddedPass(pass []byte) []byte {
|
||||||
key := make([]byte, 32)
|
key := make([]byte, 32)
|
||||||
if len(pass) >= 32 {
|
i := copy(key, pass)
|
||||||
for i := 0; i < 32; i++ {
|
for ; i < 32; i++ {
|
||||||
key[i] = pass[i]
|
key[i] = padding[i-len(pass)]
|
||||||
}
|
|
||||||
} 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)]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return key
|
return key
|
||||||
}
|
}
|
||||||
@ -64,12 +57,9 @@ func (sh stdHandlerR4) alg2(d *StdEncryptDict, pass []byte) []byte {
|
|||||||
h.Write(d.O)
|
h.Write(d.O)
|
||||||
|
|
||||||
// Pass P (Lower order byte first).
|
// Pass P (Lower order byte first).
|
||||||
var p = uint32(d.P)
|
var pb [4]byte
|
||||||
var pb []byte
|
binary.LittleEndian.PutUint32(pb[:], uint32(d.P))
|
||||||
for i := 0; i < 4; i++ {
|
h.Write(pb[:])
|
||||||
pb = append(pb, byte(((p >> uint(8*i)) & 0xff)))
|
|
||||||
}
|
|
||||||
h.Write(pb)
|
|
||||||
common.Log.Trace("go P: % x", pb)
|
common.Log.Trace("go P: % x", pb)
|
||||||
|
|
||||||
// Pass ID[0] from the trailer
|
// Pass ID[0] from the trailer
|
||||||
@ -82,8 +72,9 @@ func (sh stdHandlerR4) alg2(d *StdEncryptDict, pass []byte) []byte {
|
|||||||
hashb := h.Sum(nil)
|
hashb := h.Sum(nil)
|
||||||
|
|
||||||
if d.R >= 3 {
|
if d.R >= 3 {
|
||||||
|
h = md5.New()
|
||||||
for i := 0; i < 50; i++ {
|
for i := 0; i < 50; i++ {
|
||||||
h = md5.New()
|
h.Reset()
|
||||||
h.Write(hashb[0 : sh.Length/8])
|
h.Write(hashb[0 : sh.Length/8])
|
||||||
hashb = h.Sum(nil)
|
hashb = h.Sum(nil)
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,16 @@ import (
|
|||||||
|
|
||||||
var _ StdHandler = stdHandlerR6{}
|
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.
|
// NewHandlerR6 creates a new standard security handler for R=5 and R=6.
|
||||||
func NewHandlerR6() StdHandler {
|
func NewHandlerR6() StdHandler {
|
||||||
return stdHandlerR6{}
|
return stdHandlerR6{}
|
||||||
@ -34,6 +44,12 @@ type stdHandlerR6 struct{}
|
|||||||
// 7.6.4.3.2 Algorithm 2.A (page 83)
|
// 7.6.4.3.2 Algorithm 2.A (page 83)
|
||||||
func (sh stdHandlerR6) alg2a(d *StdEncryptDict, pass []byte) ([]byte, Permissions, 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
|
// 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
|
// step a: Unicode normalization
|
||||||
// TODO(dennwc): make sure that UTF-8 strings are normalized
|
// 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
|
ekey = d.UE
|
||||||
ukey = nil
|
ukey = nil
|
||||||
}
|
}
|
||||||
|
if err := checkAtLeast("alg2a", "Key", 32, ekey); err != nil {
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
ekey = ekey[:32]
|
ekey = ekey[:32]
|
||||||
|
|
||||||
// intermediate key
|
// intermediate key
|
||||||
@ -164,10 +183,7 @@ func alg2b(data, pwd, userKey []byte) []byte {
|
|||||||
repeat(K1, n)
|
repeat(K1, n)
|
||||||
|
|
||||||
// step b: encrypt K1 with AES-128 CBC
|
// step b: encrypt K1 with AES-128 CBC
|
||||||
ac, err := aes.NewCipher(K[0:16])
|
ac := newAESCipher(K[0:16])
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
cbc := cipher.NewCBCEncrypter(ac, K[16:32])
|
cbc := cipher.NewCBCEncrypter(ac, K[16:32])
|
||||||
cbc.CryptBlocks(K1, K1)
|
cbc.CryptBlocks(K1, K1)
|
||||||
E = 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).
|
// 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)
|
// 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 {
|
||||||
|
if err := checkAtLeast("alg8", "Key", 32, ekey); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
// step a: compute U (user password)
|
// step a: compute U (user password)
|
||||||
var rbuf [16]byte
|
var rbuf [16]byte
|
||||||
if _, err := io.ReadFull(rand.Reader, rbuf[:]); err != nil {
|
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)
|
h = sh.alg2b(d.R, str, upass, nil)
|
||||||
|
|
||||||
ac, err := aes.NewCipher(h[:32])
|
ac := newAESCipher(h[:32])
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
iv := make([]byte, aes.BlockSize)
|
iv := make([]byte, aes.BlockSize)
|
||||||
cbc := cipher.NewCBCEncrypter(ac, iv)
|
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).
|
// 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)
|
// 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 {
|
||||||
|
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)
|
// step a: compute O (owner password)
|
||||||
var rbuf [16]byte
|
var rbuf [16]byte
|
||||||
if _, err := io.ReadFull(rand.Reader, rbuf[:]); err != nil {
|
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)
|
h = sh.alg2b(d.R, str, opass, userKey)
|
||||||
|
|
||||||
ac, err := aes.NewCipher(h[:32])
|
ac := newAESCipher(h[:32])
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
iv := make([]byte, aes.BlockSize)
|
iv := make([]byte, aes.BlockSize)
|
||||||
cbc := cipher.NewCBCEncrypter(ac, iv)
|
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).
|
// alg10 computes the encryption dictionary's Perms (permissions) value (R=6).
|
||||||
// 7.6.4.4.8 Algorithm 10 (page 87)
|
// 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 {
|
||||||
|
if err := checkAtLeast("alg10", "Key", 32, ekey); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
// step a: extend permissions to 64 bits
|
// step a: extend permissions to 64 bits
|
||||||
perms := uint64(uint32(d.P)) | (math.MaxUint32 << 32)
|
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
|
// step f: encrypt permissions
|
||||||
ac, err := aes.NewCipher(ekey[:32])
|
ac := newAESCipher(ekey[:32])
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
ecb := newECBEncrypter(ac)
|
ecb := newECBEncrypter(ac)
|
||||||
ecb.CryptBlocks(Perms, Perms)
|
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.
|
// 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) {
|
||||||
|
if err := checkAtLeast("alg11", "U", 48, d.U); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
str := make([]byte, len(upass)+8)
|
str := make([]byte, len(upass)+8)
|
||||||
i := copy(str, upass)
|
i := copy(str, upass)
|
||||||
i += copy(str[i:], d.U[32:40]) // user Validation Salt
|
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.
|
// alg12 authenticates the owner password (R >= 5) and returns the hash.
|
||||||
// 7.6.4.4.10 Algorithm 12 (page 87)
|
// 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) {
|
||||||
|
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)
|
str := make([]byte, len(opass)+8+48)
|
||||||
i := copy(str, opass)
|
i := copy(str, opass)
|
||||||
i += copy(str[i:], d.O[32:40]) // owner Validation Salt
|
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.
|
// alg13 validates user permissions (P+EncryptMetadata vs Perms) for R=6.
|
||||||
// 7.6.4.4.11 Algorithm 13 (page 87)
|
// 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 {
|
||||||
|
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)
|
perms := make([]byte, 16)
|
||||||
copy(perms, d.Perms[:16])
|
copy(perms, d.Perms[:16])
|
||||||
|
|
||||||
ac, err := aes.NewCipher(fkey[:32])
|
ac, err := aes.NewCipher(fkey[:32])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
ecb := newECBDecrypter(ac)
|
ecb := newECBDecrypter(ac)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user