mirror of
https://github.com/unidoc/unipdf.git
synced 2025-05-02 22:17:06 +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:
|
case cryptFilterAESV3:
|
||||||
vers.Major, vers.Minor = 2, 0
|
vers.Major, vers.Minor = 2, 0
|
||||||
crypter.encrypt.V = 5
|
crypter.encrypt.V = 5
|
||||||
crypter.encryptStd.R = 6 // TODO(dennwc): a way to set R=5?
|
crypter.encryptStd.R = 6
|
||||||
}
|
}
|
||||||
if cf != nil {
|
if cf != nil {
|
||||||
crypter.encrypt.Length = cf.KeyLength() * 8
|
crypter.encrypt.Length = cf.KeyLength() * 8
|
||||||
@ -82,20 +82,8 @@ func PdfCryptNewEncrypt(cf CryptFilter, userPass, ownerPass []byte, perm AccessP
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
// Generate encryption parameters
|
// encode parameters generated by the Standard security handler
|
||||||
if crypter.encryptStd.R < 5 {
|
crypter.encryptStd.EncodeTo(ed)
|
||||||
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)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if crypter.encrypt.V >= 4 {
|
if crypter.encrypt.V >= 4 {
|
||||||
if err := crypter.saveCryptFilters(ed); err != nil {
|
if err := crypter.saveCryptFilters(ed); err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
@ -138,8 +126,6 @@ func (crypt *PdfCrypt) newEncyptDict() *PdfObjectDictionary {
|
|||||||
ed.Set("Filter", MakeName("Standard"))
|
ed.Set("Filter", MakeName("Standard"))
|
||||||
ed.Set("V", MakeInteger(int64(crypt.encrypt.V)))
|
ed.Set("V", MakeInteger(int64(crypt.encrypt.V)))
|
||||||
ed.Set("Length", MakeInteger(int64(crypt.encrypt.Length)))
|
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
|
return ed
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -195,17 +181,6 @@ type encryptDict struct {
|
|||||||
EFF string // The filter that shall be used when decrypting embedded file streams.
|
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.
|
// AccessPermissions is a bitmask of access permissions for a PDF file.
|
||||||
type AccessPermissions uint32
|
type AccessPermissions uint32
|
||||||
|
|
||||||
@ -429,89 +404,9 @@ func PdfCryptNewDecrypt(parser *PdfParser, ed, trailer *PdfObjectDictionary) (*P
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
R, ok := ed.Get("R").(*PdfObjectInteger)
|
// decode Standard security handler parameters
|
||||||
if !ok {
|
if err := crypter.encryptStd.DecodeFrom(ed); err != nil {
|
||||||
return crypter, errors.New("Encrypt dictionary missing R")
|
return crypter, err
|
||||||
}
|
|
||||||
// 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.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Default: empty ID.
|
// Default: empty ID.
|
||||||
|
@ -5,6 +5,13 @@
|
|||||||
|
|
||||||
package core
|
package core
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/unidoc/unidoc/common"
|
||||||
|
)
|
||||||
|
|
||||||
type stdSecurityHandler interface {
|
type stdSecurityHandler 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.
|
||||||
// It assumes that R, P and EncryptMetadata are already set.
|
// 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.
|
// In case of failed authentication, it returns empty key and zero permissions with no error.
|
||||||
Authenticate(d *stdEncryptDict, pass []byte) ([]byte, AccessPermissions, 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