github.com/phpdave11/gofpdf@v1.4.2/protect.go (about)

     1  /*
     2   * Copyright (c) 2013-2014 Kurt Jung (Gmail: kurt.w.jung)
     3   *
     4   * Permission to use, copy, modify, and distribute this software for any
     5   * purpose with or without fee is hereby granted, provided that the above
     6   * copyright notice and this permission notice appear in all copies.
     7   *
     8   * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
     9   * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
    10   * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
    11   * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
    12   * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
    13   * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
    14   * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
    15   */
    16  
    17  // PDF protection is adapted from the work of Klemen VODOPIVEC for the fpdf
    18  // product.
    19  
    20  package gofpdf
    21  
    22  import (
    23  	"crypto/md5"
    24  	"crypto/rc4"
    25  	"encoding/binary"
    26  	"math/rand"
    27  )
    28  
    29  // Advisory bitflag constants that control document activities
    30  const (
    31  	CnProtectPrint      = 4
    32  	CnProtectModify     = 8
    33  	CnProtectCopy       = 16
    34  	CnProtectAnnotForms = 32
    35  )
    36  
    37  type protectType struct {
    38  	encrypted     bool
    39  	uValue        []byte
    40  	oValue        []byte
    41  	pValue        int
    42  	padding       []byte
    43  	encryptionKey []byte
    44  	objNum        int
    45  	rc4cipher     *rc4.Cipher
    46  	rc4n          uint32 // Object number associated with rc4 cipher
    47  }
    48  
    49  func (p *protectType) rc4(n uint32, buf *[]byte) {
    50  	if p.rc4cipher == nil || p.rc4n != n {
    51  		p.rc4cipher, _ = rc4.NewCipher(p.objectKey(n))
    52  		p.rc4n = n
    53  	}
    54  	p.rc4cipher.XORKeyStream(*buf, *buf)
    55  }
    56  
    57  func (p *protectType) objectKey(n uint32) []byte {
    58  	var nbuf, b []byte
    59  	nbuf = make([]byte, 8, 8)
    60  	binary.LittleEndian.PutUint32(nbuf, n)
    61  	b = append(b, p.encryptionKey...)
    62  	b = append(b, nbuf[0], nbuf[1], nbuf[2], 0, 0)
    63  	s := md5.Sum(b)
    64  	return s[0:10]
    65  }
    66  
    67  func oValueGen(userPass, ownerPass []byte) (v []byte) {
    68  	var c *rc4.Cipher
    69  	tmp := md5.Sum(ownerPass)
    70  	c, _ = rc4.NewCipher(tmp[0:5])
    71  	size := len(userPass)
    72  	v = make([]byte, size, size)
    73  	c.XORKeyStream(v, userPass)
    74  	return
    75  }
    76  
    77  func (p *protectType) uValueGen() (v []byte) {
    78  	var c *rc4.Cipher
    79  	c, _ = rc4.NewCipher(p.encryptionKey)
    80  	size := len(p.padding)
    81  	v = make([]byte, size, size)
    82  	c.XORKeyStream(v, p.padding)
    83  	return
    84  }
    85  
    86  func (p *protectType) setProtection(privFlag byte, userPassStr, ownerPassStr string) {
    87  	privFlag = 192 | (privFlag & (CnProtectCopy | CnProtectModify | CnProtectPrint | CnProtectAnnotForms))
    88  	p.padding = []byte{
    89  		0x28, 0xBF, 0x4E, 0x5E, 0x4E, 0x75, 0x8A, 0x41,
    90  		0x64, 0x00, 0x4E, 0x56, 0xFF, 0xFA, 0x01, 0x08,
    91  		0x2E, 0x2E, 0x00, 0xB6, 0xD0, 0x68, 0x3E, 0x80,
    92  		0x2F, 0x0C, 0xA9, 0xFE, 0x64, 0x53, 0x69, 0x7A,
    93  	}
    94  	userPass := []byte(userPassStr)
    95  	var ownerPass []byte
    96  	if ownerPassStr == "" {
    97  		ownerPass = make([]byte, 8, 8)
    98  		binary.LittleEndian.PutUint64(ownerPass, uint64(rand.Int63()))
    99  	} else {
   100  		ownerPass = []byte(ownerPassStr)
   101  	}
   102  	userPass = append(userPass, p.padding...)[0:32]
   103  	ownerPass = append(ownerPass, p.padding...)[0:32]
   104  	p.encrypted = true
   105  	p.oValue = oValueGen(userPass, ownerPass)
   106  	var buf []byte
   107  	buf = append(buf, userPass...)
   108  	buf = append(buf, p.oValue...)
   109  	buf = append(buf, privFlag, 0xff, 0xff, 0xff)
   110  	sum := md5.Sum(buf)
   111  	p.encryptionKey = sum[0:5]
   112  	p.uValue = p.uValueGen()
   113  	p.pValue = -(int(privFlag^255) + 1)
   114  }