File: des.py

package info (click to toggle)
python-pysnmp4 4.1.6a-1
  • links: PTS
  • area: main
  • in suites: etch, etch-m68k
  • size: 1,016 kB
  • ctags: 1,826
  • sloc: python: 9,809; sh: 60; makefile: 11
file content (106 lines) | stat: -rw-r--r-- 3,256 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
import random, string
from pysnmp.proto.secmod.rfc3414.priv import base
from pyasn1.type import univ
from pysnmp.proto import error

try:
    from Crypto.Cipher import DES
except ImportError:
    DES = None
    
random.seed()

# 8.2.4

class Des(base.AbstractEncryptionService):
    serviceID = (1, 3, 6, 1, 6, 3, 10, 1, 2, 2) # usmDESPrivProtocol
    _localInt = long(random.random()*0xffffffffL)
    # 8.1.1.1
    def __getEncryptionKey(self, mibInstrumController, privKey):
        desKey = privKey[:8]
        preIV = privKey[8:16]

        snmpEngineBoots, = mibInstrumController.mibBuilder.importSymbols(
            '__SNMP-FRAMEWORK-MIB', 'snmpEngineBoots'
            )
        securityEngineBoots = long(snmpEngineBoots.syntax)

        salt = [
            securityEngineBoots>>24&0xff,
            securityEngineBoots>>16&0xff,
            securityEngineBoots>>8&0xff,
            securityEngineBoots&0xff,
            self._localInt>>24&0xff,
            self._localInt>>16&0xff,
            self._localInt>>8&0xff,
            self._localInt&0xff
            ]
        if self._localInt == 0xffffffffL:
            self._localInt = 0
        else:
            self._localInt = self._localInt + 1

        return desKey, \
               string.join(map(lambda x: chr(x), salt), ''), \
               string.join(map(lambda x,y: chr(x^ord(y)), salt, preIV), '')

    def __getDecryptionKey(self, mibInstrumController, privKey, salt):
        return privKey[:8], string.join(
            map(lambda x,y: chr(ord(x)^ord(y)), salt, privKey[8:16]), ''
            )
        
    # 8.2.4.1
    def encryptData(self, mibInstrumController, encryptKey, dataToEncrypt):
        if DES is None:
            raise error.StatusInformation(
                errorIndication='encryptionError'
                )
        
        # 8.3.1.1
        desKey, salt, iv = self.__getEncryptionKey(
            mibInstrumController, str(encryptKey)
            )

        # 8.3.1.2
        privParameters = univ.OctetString(salt)

        # 8.1.1.2
        desObj = DES.new(desKey, DES.MODE_CBC, iv) # XXX
        plaintext =  dataToEncrypt + '\x00' * (8 - len(dataToEncrypt) % 8)
        ciphertext = desObj.encrypt(plaintext)

        # 8.3.1.3 & 4
        return univ.OctetString(ciphertext), privParameters
        
    # 8.2.4.2
    def decryptData(self, mibInstrumController, decryptKey,
                    privParameters, encryptedData):
        if DES is None:
            raise error.StatusInformation(
                errorIndication='decryptionError'
                )
        
        # 8.3.2.1
        if len(privParameters) != 8:
            raise error.StatusInformation(
                errorIndication='decryptionError'
                )
            
        # 8.3.2.2
        salt = str(privParameters)

        # 8.3.2.3
        desKey, iv = self.__getDecryptionKey(
            mibInstrumController, str(decryptKey), salt
            )

        # 8.3.2.4 -> 8.1.1.3
        if len(encryptedData) % 8 != 0:
            raise error.StatusInformation(
                errorIndication='decryptionError'
                )

        desObj = DES.new(desKey, DES.MODE_CBC, iv)
        
        # 8.3.2.6
        return desObj.decrypt(str(encryptedData))