mirror of
https://github.com/unidoc/unipdf.git
synced 2025-05-01 22:17:29 +08:00
core: move encryption dictionary encoder and decoder to it's own type
This commit is contained in:
parent
1c19ba9e96
commit
68d20968d3
@ -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.
|
||||
|
@ -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
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user