core: move encryption dictionary encoder and decoder to it's own type

This commit is contained in:
Denys Smirnov 2018-10-03 07:59:15 +03:00
parent 1c19ba9e96
commit 68d20968d3
2 changed files with 132 additions and 111 deletions

View File

@ -50,7 +50,7 @@ func PdfCryptNewEncrypt(cf CryptFilter, userPass, ownerPass []byte, perm AccessP
case cryptFilterAESV3:
vers.Major, vers.Minor = 2, 0
crypter.encrypt.V = 5
crypter.encryptStd.R = 6 // TODO(dennwc): a way to set R=5?
crypter.encryptStd.R = 6
}
if cf != nil {
crypter.encrypt.Length = cf.KeyLength() * 8
@ -82,20 +82,8 @@ func PdfCryptNewEncrypt(cf CryptFilter, userPass, ownerPass []byte, perm AccessP
if err != nil {
return nil, nil, err
}
// Generate encryption parameters
if crypter.encryptStd.R < 5 {
ed.Set("O", MakeString(string(crypter.encryptStd.O)))
ed.Set("U", MakeString(string(crypter.encryptStd.U)))
} else { // R >= 5
ed.Set("O", MakeString(string(crypter.encryptStd.O)))
ed.Set("U", MakeString(string(crypter.encryptStd.U)))
ed.Set("OE", MakeString(string(crypter.encryptStd.OE)))
ed.Set("UE", MakeString(string(crypter.encryptStd.UE)))
ed.Set("EncryptMetadata", MakeBool(crypter.encryptStd.EncryptMetadata))
if crypter.encryptStd.R > 5 {
ed.Set("Perms", MakeString(string(crypter.encryptStd.Perms)))
}
}
// encode parameters generated by the Standard security handler
crypter.encryptStd.EncodeTo(ed)
if crypter.encrypt.V >= 4 {
if err := crypter.saveCryptFilters(ed); err != nil {
return nil, nil, err
@ -138,8 +126,6 @@ func (crypt *PdfCrypt) newEncyptDict() *PdfObjectDictionary {
ed.Set("Filter", MakeName("Standard"))
ed.Set("V", MakeInteger(int64(crypt.encrypt.V)))
ed.Set("Length", MakeInteger(int64(crypt.encrypt.Length)))
ed.Set("P", MakeInteger(int64(crypt.encryptStd.P)))
ed.Set("R", MakeInteger(int64(crypt.encryptStd.R)))
return ed
}
@ -195,17 +181,6 @@ type encryptDict struct {
EFF string // The filter that shall be used when decrypting embedded file streams.
}
// stdEncryptDict is a set of additional fields used in standard encryption dictionary.
type stdEncryptDict struct {
R int // (Required) A number specifying which revision of the standard security handler shall be used.
O, U []byte
OE, UE []byte // R=6
P AccessPermissions
Perms []byte // An encrypted copy of P (16 bytes). Used to verify permissions. R=6
EncryptMetadata bool // Indicates whether the document-level metadata stream shall be encrypted.
}
// AccessPermissions is a bitmask of access permissions for a PDF file.
type AccessPermissions uint32
@ -429,89 +404,9 @@ func PdfCryptNewDecrypt(parser *PdfParser, ed, trailer *PdfObjectDictionary) (*P
}
}
R, ok := ed.Get("R").(*PdfObjectInteger)
if !ok {
return crypter, errors.New("Encrypt dictionary missing R")
}
// TODO(dennwc): according to spec, R should be validated according to V value
if *R < 2 || *R > 6 {
return crypter, fmt.Errorf("Invalid R (%d)", *R)
}
crypter.encryptStd.R = int(*R)
O, ok := ed.Get("O").(*PdfObjectString)
if !ok {
return crypter, errors.New("Encrypt dictionary missing O")
}
if crypter.encryptStd.R == 5 || crypter.encryptStd.R == 6 {
// the spec says =48 bytes, but Acrobat pads them out longer
if len(O.Str()) < 48 {
return crypter, fmt.Errorf("Length(O) < 48 (%d)", len(O.Str()))
}
} else if len(O.Str()) != 32 {
return crypter, fmt.Errorf("Length(O) != 32 (%d)", len(O.Str()))
}
crypter.encryptStd.O = O.Bytes()
U, ok := ed.Get("U").(*PdfObjectString)
if !ok {
return crypter, errors.New("Encrypt dictionary missing U")
}
if crypter.encryptStd.R == 5 || crypter.encryptStd.R == 6 {
// the spec says =48 bytes, but Acrobat pads them out longer
if len(U.Str()) < 48 {
return crypter, fmt.Errorf("Length(U) < 48 (%d)", len(U.Str()))
}
} else if len(U.Str()) != 32 {
// Strictly this does not cause an error.
// If O is OK and others then can still read the file.
common.Log.Debug("Warning: Length(U) != 32 (%d)", len(U.Str()))
//return crypter, errors.New("Length(U) != 32")
}
crypter.encryptStd.U = U.Bytes()
if crypter.encryptStd.R >= 5 {
OE, ok := ed.Get("OE").(*PdfObjectString)
if !ok {
return crypter, errors.New("Encrypt dictionary missing OE")
}
if len(OE.Str()) != 32 {
return crypter, fmt.Errorf("Length(OE) != 32 (%d)", len(OE.Str()))
}
crypter.encryptStd.OE = OE.Bytes()
UE, ok := ed.Get("UE").(*PdfObjectString)
if !ok {
return crypter, errors.New("Encrypt dictionary missing UE")
}
if len(UE.Str()) != 32 {
return crypter, fmt.Errorf("Length(UE) != 32 (%d)", len(UE.Str()))
}
crypter.encryptStd.UE = UE.Bytes()
}
P, ok := ed.Get("P").(*PdfObjectInteger)
if !ok {
return crypter, errors.New("Encrypt dictionary missing permissions attr")
}
crypter.encryptStd.P = AccessPermissions(*P)
if crypter.encryptStd.R == 6 {
Perms, ok := ed.Get("Perms").(*PdfObjectString)
if !ok {
return crypter, errors.New("Encrypt dictionary missing Perms")
}
if len(Perms.Str()) != 16 {
return crypter, fmt.Errorf("Length(Perms) != 16 (%d)", len(Perms.Str()))
}
crypter.encryptStd.Perms = Perms.Bytes()
}
em, ok := ed.Get("EncryptMetadata").(*PdfObjectBool)
if ok {
crypter.encryptStd.EncryptMetadata = bool(*em)
} else {
crypter.encryptStd.EncryptMetadata = true // True by default.
// decode Standard security handler parameters
if err := crypter.encryptStd.DecodeFrom(ed); err != nil {
return crypter, err
}
// Default: empty ID.

View File

@ -5,6 +5,13 @@
package core
import (
"errors"
"fmt"
"github.com/unidoc/unidoc/common"
)
type stdSecurityHandler interface {
// GenerateParams uses owner and user passwords to set encryption parameters and generate an encryption key.
// It assumes that R, P and EncryptMetadata are already set.
@ -15,3 +22,122 @@ type stdSecurityHandler interface {
// In case of failed authentication, it returns empty key and zero permissions with no error.
Authenticate(d *stdEncryptDict, pass []byte) ([]byte, AccessPermissions, error)
}
// stdEncryptDict is a set of additional fields used in standard encryption dictionary.
type stdEncryptDict struct {
R int // (Required) A number specifying which revision of the standard security handler shall be used.
P AccessPermissions
EncryptMetadata bool // Indicates whether the document-level metadata stream shall be encrypted.
// set by security handlers:
O, U []byte
OE, UE []byte // R=6
Perms []byte // An encrypted copy of P (16 bytes). Used to verify permissions. R=6
}
func (d *stdEncryptDict) EncodeTo(ed *PdfObjectDictionary) {
ed.Set("R", MakeInteger(int64(d.R)))
ed.Set("P", MakeInteger(int64(d.P)))
ed.Set("O", MakeStringFromBytes(d.O))
ed.Set("U", MakeStringFromBytes(d.U))
if d.R >= 5 {
ed.Set("OE", MakeStringFromBytes(d.OE))
ed.Set("UE", MakeStringFromBytes(d.UE))
ed.Set("EncryptMetadata", MakeBool(d.EncryptMetadata))
if d.R > 5 {
ed.Set("Perms", MakeStringFromBytes(d.Perms))
}
}
}
func (d *stdEncryptDict) DecodeFrom(ed *PdfObjectDictionary) error {
// TODO(dennwc): this code is too verbose; maybe use reflection to populate fields and validate afterwards?
R, ok := ed.Get("R").(*PdfObjectInteger)
if !ok {
return errors.New("Encrypt dictionary missing R")
}
// TODO(dennwc): according to spec, R should be validated according to V value
if *R < 2 || *R > 6 {
return fmt.Errorf("Invalid R (%d)", *R)
}
d.R = int(*R)
O, ok := ed.Get("O").(*PdfObjectString)
if !ok {
return errors.New("Encrypt dictionary missing O")
}
if d.R == 5 || d.R == 6 {
// the spec says =48 bytes, but Acrobat pads them out longer
if len(O.Str()) < 48 {
return fmt.Errorf("Length(O) < 48 (%d)", len(O.Str()))
}
} else if len(O.Str()) != 32 {
return fmt.Errorf("Length(O) != 32 (%d)", len(O.Str()))
}
d.O = O.Bytes()
U, ok := ed.Get("U").(*PdfObjectString)
if !ok {
return errors.New("Encrypt dictionary missing U")
}
if d.R == 5 || d.R == 6 {
// the spec says =48 bytes, but Acrobat pads them out longer
if len(U.Str()) < 48 {
return fmt.Errorf("Length(U) < 48 (%d)", len(U.Str()))
}
} else if len(U.Str()) != 32 {
// Strictly this does not cause an error.
// If O is OK and others then can still read the file.
common.Log.Debug("Warning: Length(U) != 32 (%d)", len(U.Str()))
//return crypter, errors.New("Length(U) != 32")
}
d.U = U.Bytes()
if d.R >= 5 {
OE, ok := ed.Get("OE").(*PdfObjectString)
if !ok {
return errors.New("Encrypt dictionary missing OE")
}
if len(OE.Str()) != 32 {
return fmt.Errorf("Length(OE) != 32 (%d)", len(OE.Str()))
}
d.OE = OE.Bytes()
UE, ok := ed.Get("UE").(*PdfObjectString)
if !ok {
return errors.New("Encrypt dictionary missing UE")
}
if len(UE.Str()) != 32 {
return fmt.Errorf("Length(UE) != 32 (%d)", len(UE.Str()))
}
d.UE = UE.Bytes()
}
P, ok := ed.Get("P").(*PdfObjectInteger)
if !ok {
return errors.New("Encrypt dictionary missing permissions attr")
}
d.P = AccessPermissions(*P)
if d.R == 6 {
Perms, ok := ed.Get("Perms").(*PdfObjectString)
if !ok {
return errors.New("Encrypt dictionary missing Perms")
}
if len(Perms.Str()) != 16 {
return fmt.Errorf("Length(Perms) != 16 (%d)", len(Perms.Str()))
}
d.Perms = Perms.Bytes()
}
em, ok := ed.Get("EncryptMetadata").(*PdfObjectBool)
if ok {
d.EncryptMetadata = bool(*em)
} else {
d.EncryptMetadata = true // True by default.
}
return nil
}