5

We have a Delphi 2007 routine used to encrypt passwords in a table. The routine was originally grabbed from a CompuServe post a decade or more ago, and a significant amount of data encrypted with this routine exists.

The heart of the original routine is this:

chr(ord(Str[I]) xor not(ord(Id[I mod length(Id) + 1])));

I knew the conversion to Delphi XE would be problematic because of Unicode, so I broke that code out into a function that displays each step of the calculations in a memo:

function TfrmMain.EncodeDecode(AString: string): string;
const
  Hash: string = '^%12h2DBC3f41~~#6093fn7mY7eujEhbFD3DZ|R9aSDVvUY@dk79*7a-|-  Q';
var
  I: Integer;
  IMod: Integer;
  HMod: Char;
  OMod: Integer;
  AStrI: Char;
  OStrI: Integer;
  ResultStr: string;
  XOrNot: Integer;
  ChrXN: AnsiChar;
begin
  Memo1.Clear;
  Memo1.Lines.Add ('AStrI' + TAB + 'IMod' + TAB + 'HMod' +
    TAB + 'OMod' + TAB + 'OStrI' + TAB + 'XOrNot' + TAB + 'ChrXN');

  for I := 1 to Length (AString) do
  begin
    IMod := I mod Length (Hash) + 1;
    HMod := Hash [IMod];
    OMod := Ord (HMod);
    AStrI := AString[I];
    OStrI := Ord (AStrI);  // This is where things go south
    XOrNot := OStrI xor not OMod;
    ChrXN := AnsiChar (XOrNot);
    ResultStr := ResultStr + ChrXN;

    Memo1.Lines.Add (AStrI  + TAB +
      IntToStr (IMod)   + TAB +
      HMod              + TAB +
      IntToStr (OMod)   + TAB +
      IntToStr (OStrI)  + TAB +
      IntToStr (XOrNot) + TAB +
      ChrXN);
  end;
  Memo1.Lines.Add (ResultStr);
  Result := ResultStr;
end;

Like ROT13, the same routine is used to both encrypt and decrypt. If I feed it a string like 'ABCDEFGHI', the Delphi 2007 version can take the resulting encrypted string, run it through the same routine, and get back the original string. The version in Delphi XE, however, doesn't quite work. I've made some tweaks (included above) to improve it, but on the OstrI step it falls apart. I think it has something to do with performing an Ord on a (Wide) Char, but that's the closest I can get.

Any advice greatly appreciated.


Edited

Here is the original Delphi 2007 code:

function EncodeDecode(Str: string): string;
const
  Id: string = '^%12h2DBC3f41~~#6093fn7mY7eujEhbFD3DZ|R9aSDVvUY@dk79*7a-|-  Q';
var
  I: Integer;
begin
  for I := 1 to Length (Str) do
    Str[I] := chr (ord (Str[I]) xor not (ord (Id[I mod Length (Id) + 1])));
  Result := Str;
end;

We actually have to convert this not only to Delphi XE for new versions of our existing software, but also to C# for a new web-based front end.

8
  • To put it more succinctly: the function is an involution (= its own inverse). Commented Jul 7, 2011 at 19:08
  • I haven't studied the code above in detail, but I see you are mixing string and AnsiString (and char and AnsiChar), which generally isn't great when dealing with the raw, binary, data. But perhaps you are aware of this and is only doing things the right way? Commented Jul 7, 2011 at 19:12
  • Instead of posting your code that doesn't work, could you just post the D2007 code and one of use will be able to show you how to port it to XE. Commented Jul 7, 2011 at 19:16
  • Original post edited to include the starting D2007 code. Thanks @DavidHeffernan and good luck :-) Commented Jul 7, 2011 at 19:39
  • 1
    @Eric: You sure know how to make things complicated! ;) Commented Jul 7, 2011 at 19:47

1 Answer 1

8

Simple approach is, in essence, as follows:

  1. Start with the Delphi 2007 code.
  2. Change string to AnsiString.
  3. Change Char to AnsiChar.
  4. Possibly change Chr() to AnsiChar().

There may be more nuances to your code. Ideally I'd like to see the original Delphi 2007 version of the code.


Having posted the original code, I think you should can use this routine in XE:

function EncodeDecode(const Str: AnsiString): AnsiString;
const
  Id: AnsiString = '^%12h2DBC3f41~~#6093fn7mY7eujEhbFD3DZ|R9aSDVvUY@dk79*7a-|-  Q';
var
  I: Integer;
begin
  Result := Str;
  for I := 1 to Length(Result) do
    Result[I] := AnsiChar(ord(Result[I]) xor not (ord(Id[I mod Length (Id) + 1])));
end;

Note that I changed the code to take input as a const string and to use Result as the working buffer. This is not necessary for your ANSI/Unicode needs, but feels more natural to me!

Sign up to request clarification or add additional context in comments.

8 Comments

This is always a way of making pre-Unicode Delphi code work in a modern version of Delphi. The only (and obvious) downside is that you do not gain Unicode support.
@Andreas I guess it's OK in this case for OP since OP has data locked in files that is limited to ANSI.
Wow, I was way over-thinking the problem. Thank you David for the quick answer!
@David: to take your suggestion a step further, I would suggest changing the input/output values from AnsiString to RawByteString. Prior to D2009, AnsiString did not really make any assumptions about the codepage used to encode the characters. In D2009 onwards, it does, whereas RawByteString inherits the codepage of whatever Ansi string is passed to it.
@Remy I figured codepages wouldn't be an issue when using the AnsiString as a byte buffer. But I'm no expert on such nuances. What problems could arise from using AnsiString rather than RawBytesString?
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.