hur.cn - 华软源码

 热门搜索
The Unofficial Newsletter of Delphi Users - by Robert Vivrette


Simple Text Encryption With Delphi

by Robert Vivrette - RobertV@mail.com

There must be something in the water! Within the last week or so I have had about 4 or 5 emails on how to do text encryption. I figured that since there was so much interest, I might as well put something together! Here it goes...

Basically, encrypting text can take many forms, and the one presented below is one of the simpler methods. It is sophisticated enough to keep honest people honest, but anyone who is determined to break the encryption could probably come up with program that could try random passwords and eventually break it.

To encrypt a piece of text, essentially you want to scramble the characters in a way that you can unscramble with no loss of data (i.e. all the characters are restored). One of the techniques I use is bit shifting. Essentially, I take the character as a byte value and shift its bits left or right. Any bits that are shifted off either end of the byte are placed back on the opposite side. Simply picture a row of 8 binary digits and imagine them rotating in one direction or the other a certain number of positions. For example, the value '01010011' rotated left 3 bits would be '10011010'. Notice how the bits shifted off the left came back on to the right side. Now if we were to rotate those back 3 bits to the right, the original value would be restored.

So first, I have put together a function that will take a character, rotate it a certain number of bits in either direction, and return the resulting encrypted character.

Function RotateBits(C: Char; Bits: Integer): Char;
var
  SI : Word;
begin
  Bits := Bits mod 8;
  // Are we shifting left?
  if Bits < 0 then
    begin
      // Put the data on the right half of a Word (2 bytes)
      SI := MakeWord(Byte(C),0);
      // Now shift it left the appropriate number of bits
      SI := SI shl Abs(Bits);
    end
  else
    begin
      // Put the data on the left half of a Word (2 bytes)
      SI := MakeWord(0,Byte(C));
      // Now shift it right the appropriate number of bits
      SI := SI shr Abs(Bits);
    end;
  // Now OR the two halves together
  SI := Lo(SI) or Hi(SI);
  Result := Chr(SI);
end;
First, we limit the value in bits to shifting no more than 8 bits in either direction. If the value of bits is negative it indicates a left shift. If it is positive, it indicates a right shift. By using the mod function, it makes sure that Bits is within the range of plus or minus 0 to 7.

Next, I take the byte and put it in the left or right side of a word value. Since the word holds 2 bytes, I am going to use its 2nd byte to hold the bits that have been shifted off the original byte. If I am going to shift left, I put my value in the right half of the Word. If I am going to shift right, I put it in the left half of the Word. Then I use shl or shr (Shift Left or Shift Right) as appropriate. Finally, to combine the two back together into a single value, I use the OR operator on both the hi-order and lo-order bytes of the Word. This has the effect of combining them back together into a byte value. I then cast the result as a Char value and return.

Next comes the main routine to do the encoding and decoding. Looks a little complex, but is actually quite simple...

Function EncryptionWithPassword(Str,Pwd: String; Encode: Boolean): String;
var
  a,PwdChk,Direction,ShiftVal,PasswordDigit : Integer;
begin
  PasswordDigit := 1;
  PwdChk := 0;
  for a := 1 to Length(Pwd) do Inc(PwdChk,Ord(Pwd[a]));
  Result := Str;
  if Encode then Direction := -1 else Direction := 1;
  for a := 1 to Length(Result) do
    begin
      if Length(Pwd)=0 then
        ShiftVal := a
      else
        ShiftVal := Ord(Pwd[PasswordDigit]);
      if Odd(A) then
        Result[A] := RotateBits(Result[A],-Direction*(ShiftVal+PwdChk))
      else
        Result[A] := RotateBits(Result[A],Direction*(ShiftVal+PwdChk));
      inc(PasswordDigit);
      if PasswordDigit > Length(Pwd) then PasswordDigit := 1;
    end;
end;
Notice that the routine accepts the original string (Str), a password (Pwd) and a boolean value (Encode) that tells the function whether we want to encode or decode the text. The routine will use a password if provided, but one is not necessary.

The first thing I do is look at the password and add up all of its characters mathematically. This generates a kind-of "checksum" which is used to provide additional scrambling of the data. Without using this value, I found that passwords that were partially right (for example, using '12345' if the password was actually '123456') did manage to decode most of the text... obviously not a good solution.

Now it is just a matter of running through each character in the string and mangling it according to the RotateBits function. I first determine the amount that I am going to shift the bits by. If a password is provided, I use a character of the password and convert it to its ordinal ASCII value (i.e. 'A' is equal to ASCII 65). Each time through the routine I use the next character in the password starting back at the beginning once I get to the end of the password. If no password is provided, I set my shift value equal to the number of how far I am into the string. For example, if I am on the first character, I would use a 1, the second character I would use a 2 and so on.

Now, if I am on an odd numbered character in the string (i.e. the 1st, 3rd, 5th, etc) I am going to rotate the bits to the left. If I am on an even character, I will rotate the bits to the right. The total number of bit positions I will rotate is equal to my shift value I calculated earlier added to the password checksum value calculated at the start of the routine. Even though this number could be quite large, remember it gets chopped down to the range of -7 to 7 once it gets into the RotateBits function. The direction value simply flips the sign on the number of bit positions I am shifting to select encoding or decoding.

That's it! I don't claim that this is a foolproof encoding/decoding system, but it will work under most circumstances and is only a minor amount of code. Maybe this will spark people wanting to share their own techniques for encryption!

If you want to download the source code for this demo... click here.