class Cipher::DES

Brief

The Cipher::DES class allows for encryption and decryption of plain text using the “Data Encryption Standard”. This version is the modified version which is part of the VNC authentication scheme.

Usage is pretty straight forward:

des = Cipher::DES.new 'mysecretkey', :encrypt
str = des.update 'plain text'
str << des.update 'more plain text'
str << final

Or just use the shortcut class methods:

str = Cipher::DES.encrypt 'mysecretkey', 'plain text'

About

This code was ported from the file “d3des.c”, for portability reasons. It is not expected to be quick, but is only being used currently for the VNC authentication handshake. If you wanted to cipher a lot of text, you should probably compile the original C as an extension.

I’ve included the following copyright info from the C source verbatim:

This is D3DES (V5.09) by Richard Outerbridge with the double and
triple-length support removed for use in VNC.  Also the bytebit[] array
has been reversed so that the most significant bit in each byte of the
key is ignored, not the least significant.

These changes are:
Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.

This software is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

D3DES (V5.09)

A portable, public domain, version of the Data Encryption Standard.

Written with Symantec's THINK (Lightspeed) C by Richard Outerbridge.
Thanks to: Dan Hoey for his excellent Initial and Inverse permutation
code;  Jim Gillogly & Phil Karn for the DES key schedule code; Dennis
Ferguson, Eric Young and Dana How for comparing notes; and Ray Lau,
for humouring me on.

Copyright (c) 1988,1989,1990,1991,1992 by Richard Outerbridge.
(GEnie : OUTER; CIS : [71755,204]) Graven Imagery, 1992.

Constants

BIGBYTE
BLOCK_SIZE
BYTEBIT
PC1

Use the key schedule specified in the Standard (ANSI X3.92-1981).

PC2
SP1
SP2
SP3
SP4
SP5
SP6
SP7
SP8
TOTROT

Attributes

key[R]
mode[R]

Public Class Methods

decrypt(key, data) click to toggle source

A shortcut method to create a cipher object using key, and fully decrypt data

# File lib/cipher/des.rb, line 114
def self.decrypt key, data
  des = new key, :decrypt
  des.update(data) << des.final
end
encrypt(key, data) click to toggle source

A shortcut method to create a cipher object using key, and fully encrypt data

# File lib/cipher/des.rb, line 108
def self.encrypt key, data
  des = new key, :encrypt
  des.update(data) << des.final
end
new(key, mode) click to toggle source

Create a des cipher object. key should be cipher key to use, and mode should be either :encrypt or :decrypt.

It will expand key to be 8 bytes by padding with null bytes. If it is longer than 8 bytes, the additional data is discarded.

# File lib/cipher/des.rb, line 64
def initialize key, mode
  unless [:encrypt, :decrypt].include? mode
    raise ArgumentError, 'invalid mode argument - %s' % mode
  end
  @mode = mode

  # ensure key is 8 bytes. pad with nulls as needed
  key = key[0, BLOCK_SIZE]
  key << 0.chr * (BLOCK_SIZE - key.length)
  @key = key

  # now expand the key schedule
  @keys = self.class.send :prepare_key_stage2, self.class.send(:prepare_key_stage1, key, mode)

  # this internal buffer is used because we must process data in chunks of 8 bytes
  @buf = ''
end

Public Instance Methods

final() click to toggle source

This flushes the internal buffer by padding it out with null bytes, and doing a final DES round. Note that this means the ciphered text is always padded out to a multiple of 8 bytes.

# File lib/cipher/des.rb, line 99
def final
  if @buf.empty?
    ''
  else
    update 0.chr * (BLOCK_SIZE - @buf.length)
  end
end
update(data) click to toggle source

This updates the cipher with data, returning any available ciphered output. The data is processed in blocks of 8 bytes, so any residual is added to an internal buffer.

# File lib/cipher/des.rb, line 84
def update data
  result = ''
  data = @buf + data unless @buf.empty?
  num_blocks, residual = data.length.divmod BLOCK_SIZE
  num_blocks.times do |i|
    block = data[i * BLOCK_SIZE, BLOCK_SIZE].unpack('N2')
    result << self.class.send(:desfunc, block, @keys).pack('N2')
  end
  @buf = residual == 0 ? '' : data[-residual..-1]
  result
end