Or introduce the @:
var a := “unencrypted string”;
var b := @“encrypted string”
This give the possibility to encrypt only sensitive strings.
Or introduce the @:
var a := “unencrypted string”;
var b := @“encrypted string”
This give the possibility to encrypt only sensitive strings.
Thanks, logged as bugs://80510 (string obfuscation)
I would suggest both of the above:
[Assembly:EncryptStrings] to encrypt all strings (marked for encryption or not)
[EncryptStrings] to do this on class or method level
@ to encrypt one specific string
and one more, only method level: [DoNotEncrypt]
for methods that have heavy fixed string manipulation.
EncryptStrings would probably best be a property of the Obfuscate
attribute.
I’m not sure I like @
. For one, it already has a meaning in Pascal (address of), for another, we cant use it in C# because there @
already is a valid string prefix to disable escape chars (plus, it would be confusing for the same prefix to have different meanings in Pascal vs C#, for those of us who use both ;). But if we can diff a different prefix char, I’m all for the general syntax.
You are correct.
@ was just an idea - any prefix (or whatever to encrypt one string) will do.
We could also use the ` character (instead of ") for an encrypted string.
Or even an attribute ON the string const
writeLn([Obfuscate]"secret string");
Very nice!
Carlo, I was thinking that encryption is indeed too much overhead.
But the goal is to make it unreadable - we could use a byte array for this.
So in the code a string will get the form of:
var myString := obfuscatedfunction([77, 0, 0, 0, 121, 0, 0, 0, 83, 0, 0, 0, 116, 0, 0, 0, 114, 0, 0, 0, 105, 0, 0, 0, 110, 0, 0, 0, 103, 0, 0, 0]);
instead of
var myString := “MyString”;
This will make it 100% unreadable.
Edit: Timing on this call: only 2 ms (on an 8 year old 2 Ghz AMD Opteron machine with 1333 Mhz DDR3 memory)
Yeah. something like that.
Just tested: it works.
bugs://80509 got closed with status fixed.
For string obfuscation:
namespace RemObjects.Elements.Obfuscation;
uses
RemObjects.Elements.Cirrus.*;
type
[MethodAspectAttribute(typeOf(RemObjects.Elements.Obfuscation.__Global), true, 'ObfuscateString', 0, [typeOf(String)])]
StringObfuscationAspect = public class(IMethodCallDecorator, IAspectFinishCallback)
private
class var fRandom: Random := new Random();
class var fObfuscatedString: IFieldDefinition;
class var fDemangleString: IMethodDefinition;
class var fCtor: IMethodDefinition;
class var fValue: String;
class method MangleString(s: String; aKey: Integer): String;
begin
var c := new Char[s.Length + 2];
var lLen := s.Length xor aKey;
c[0] := Char(lLen);
c[1] := Char(lLen shr 16);
aKey := ((aKey shl 3) or (aKey shr 29)) + s.Length;
for i: Integer := 0 to s.Length -1 do begin
c[i + 2] := Char(Word(s[i]) xor aKey);
aKey := ((aKey shl 3) or (aKey shr 29)) + ord(s[i]);
end;
exit new String(c);
end;
public
method Finish(services: IServices);
begin
if fObfuscatedString <> nil then
fCtor.ReplaceMethodBody(new BeginStatement(
new PlaceHolderStatement,
new AssignmentStatement(new FieldValue(new TypeValue(fObfuscatedString.Owner), fObfuscatedString), fValue)));
fObfuscatedString := nil;
end;
method ProcessMethodCall(aContext: IContext; aMethod: IMethod; aValue: ParameterizedValue): Value;
begin
if aValue.Parameters.Count <> 1 then begin
aContext.Services.EmitError('Single string parameter expected!');
exit
end;
var lVal := aValue.Parameters[0];
if lVal.Kind <> ValueKind.Data then begin
aContext.Services.EmitError('Single string parameter expected!');
exit
end;
var lStringValue := String(lVal);
if fObfuscatedString = nil then begin
var lTD := coalesce(
ITypeDefinition(aContext.Services.FindType('<PrivateImplementationDetails>')),
aContext.Services.CreateTypeDefinition('', '<PrivateImplementationDetails>', TypeDefKind.Class));
fCtor := coalesce(lTD.GetClassConstructor as IMethodDefinition, lTD.AddConstructor(true));
fObfuscatedString := lTD.AddField('data', aContext.Services.GetBaseType(13), true);
// TODO: Java, Toffee implementation.
fDemangleString := lTD.AddMethod('a', aContext.Services.GetBaseType(13), true);
//fDemangleString.AddParameter('a', ParameterModifier.In, aContext.Services.GetBaseType(13));
fDemangleString.AddParameter('b', ParameterModifier.In, aContext.Services.GetBaseType(7));
fDemangleString.AddParameter('d', ParameterModifier.In, aContext.Services.GetBaseType(7));
var parameter := new FieldValue(new TypeValue(fObfuscatedString.Owner), fObfuscatedString);
var parameter2 := fDemangleString.GetParameter('b');
var parameter3 := fDemangleString.GetParameter('d');
/*
class method DemangleString(aIn: String; aOffset, aKey: Integer): String;
begin
var lLen := Word(aIn[aOffset + 0]) or (Integer(aIn[aOffset + 1]) shl 16);
lLen := lLen xor aKey;
aKey := ((aKey shl 3) or (aKey shr 29)) + lLen;
var c := new Char[lLen];
for i: Integer := 0 to lLen -1 do begin
c[i] := Char(Word(aIn[i + aOffset + 2]) xor aKey);
aKey := ((aKey shl 3) or (aKey shr 29)) + ord(c[i]);
end;
exit new String(c);
end;
*/
fDemangleString.ReplaceMethodBody(new BeginStatement([
new LocalVariable("lLen", fDemangleString.GetContextType("System.Int32")),
new LocalVariable("c", fDemangleString.GetContextType("array of System.Char"))
],
new AssignmentStatement(new NamedLocalValue("lLen"), new BinaryValue(new UnaryValue(new ProcValue(parameter, "get_Chars", new IType[0], false, new BinaryValue(parameter2, new DataValue(fDemangleString.GetContextType("System.Int32"), 0), BinaryOperator.Add, fDemangleString.GetContextType("System.Int32"))), UnaryOperator.ImpCast, fDemangleString.GetContextType("System.UInt16")), new BinaryValue(new UnaryValue(new ProcValue(parameter, "get_Chars", new IType[0], false, new BinaryValue(parameter2, new DataValue(fDemangleString.GetContextType("System.Int32"), 1), BinaryOperator.Add, fDemangleString.GetContextType("System.Int32"))), UnaryOperator.ImpCast, fDemangleString.GetContextType("System.Int32")), new DataValue(fDemangleString.GetContextType("System.Int32"), 16), BinaryOperator.Shl, fDemangleString.GetContextType("System.Int32")), BinaryOperator.Or, fDemangleString.GetContextType("System.Int32"))),
new AssignmentStatement(new IdentifierValue("lLen"), new BinaryValue(new IdentifierValue("lLen"), parameter3, BinaryOperator.Xor, fDemangleString.GetContextType("System.Int32"))),
new AssignmentStatement(parameter3, new BinaryValue(new BinaryValue(new BinaryValue(parameter3, new DataValue(fDemangleString.GetContextType("System.Int32"), 3), BinaryOperator.Shl, fDemangleString.GetContextType("System.Int32")), new BinaryValue(parameter3, new DataValue(fDemangleString.GetContextType("System.Int32"), 29), BinaryOperator.Shr, fDemangleString.GetContextType("System.Int32")), BinaryOperator.Or, fDemangleString.GetContextType("System.Int32")), new IdentifierValue("lLen"), BinaryOperator.Add, fDemangleString.GetContextType("System.Int32"))),
new AssignmentStatement(new NamedLocalValue("c"), new ArrayCtorCallValue(IArrayType(fDemangleString.GetContextType("array of System.Char")), new IdentifierValue("lLen"))),
new ForStatement("i", fDemangleString.GetContextType("System.Int32"), new DataValue(fDemangleString.GetContextType("System.Int32"), 0), new BinaryValue(new IdentifierValue("lLen"), new DataValue(fDemangleString.GetContextType("System.Int32"), 1), BinaryOperator.Sub, fDemangleString.GetContextType("System.Int32")), nil, new BeginStatement(new AssignmentStatement(new SubArrayValue(new IdentifierValue("c"), new IdentifierValue("i")), new UnaryValue(new BinaryValue(new UnaryValue(new ProcValue(parameter, "get_Chars", new IType[0], false, new BinaryValue(new BinaryValue(new IdentifierValue("i"), parameter2, BinaryOperator.Add, fDemangleString.GetContextType("System.Int32")), new DataValue(fDemangleString.GetContextType("System.Int32"), 2), BinaryOperator.Add, fDemangleString.GetContextType("System.Int32"))), UnaryOperator.ImpCast, fDemangleString.GetContextType("System.UInt16")), parameter3, BinaryOperator.Xor, fDemangleString.GetContextType("System.Int32")), UnaryOperator.ImpCast, fDemangleString.GetContextType("System.Char"))), new AssignmentStatement(parameter3, new BinaryValue(new BinaryValue(new BinaryValue(parameter3, new DataValue(fDemangleString.GetContextType("System.Int32"), 3), BinaryOperator.Shl, fDemangleString.GetContextType("System.Int32")), new BinaryValue(parameter3, new DataValue(fDemangleString.GetContextType("System.Int32"), 29), BinaryOperator.Shr, fDemangleString.GetContextType("System.Int32")), BinaryOperator.Or, fDemangleString.GetContextType("System.Int32")), new UnaryValue(new SubArrayValue(new IdentifierValue("c"), new IdentifierValue("i")), UnaryOperator.ImpCast, fDemangleString.GetContextType("System.UInt16")), BinaryOperator.Add, fDemangleString.GetContextType("System.Int32")))), false, false),
new ExitStatement(new NewValue(fDemangleString.GetContextType("System.String"), [new IdentifierValue("c")], new System.Collections.Generic.KeyValuePair<String, Value>[0]))));
end;
var lOffset: Integer;
var lKey := fRandom.Next;
if fValue = nil then begin
fValue := MangleString(lStringValue, lKey);
lOffset := 0;
end else begin
var lOld := fValue;
lOffset := lOld.Length;
fValue := lOld + MangleString(lStringValue, lKey);
end;
exit new ProcValue(new TypeValue(fDemangleString.Owner), fDemangleString, [lOffset, lKey]);
end;
end;
method ObfuscateString(s: String): String;
begin
exit s;
end;
end.
(.NET only at the moment, but that’s just a question of porting the code)
Usage: put it in a dll, use it like:
type
Program = class
public
class method Main(args: array of String): Int32;
begin
writeLn(ObfuscateString('HAHA'));
writeLn(ObfuscateString('HIHI'));
// add your own code here
writeLn('The magic happens here.');
end;
end;
end result looks like:
public static int Main(string[] args)
{
Console.Out.WriteLine(<PrivateImplementationDetails>.a(0, 1325031605));
Console.Out.WriteLine(<PrivateImplementationDetails>.a(6, 1888006488));
Console.Out.WriteLine("The magic happens here.");
int result = default(int);
return result;
}
a single string is stored as "悱仺צⷺvɹ녜炈誏\rȡᏙ"
this needs todays build to compile
This works on all 4 platforms now, and is integrated in cirrus.
Almost forgot to test this one …
I have to add RemObjects.Elements.Obfuscation the uses.
And it works!
@ck,
The obfuscation call fails during compile after I added it to all strings in a unit .
buildLog:
buildLog.txt (9.4 KB)
Extra info:
I have this string:
var ConStr := "Persist Security Info=true;server=" + Server +
";Initial Catalog=" + Db +
";Application Name=" + system.Reflection.Assembly.GetExecutingAssembly().FullName +
";MultipleActiveResultSets=True;Pooling=false;" as SafeString; //safestring = not nullable string
Add the first:
var ConStr := "Persist Security Info=true;server=" + Server +
ObfuscateString(";Initial Catalog=") + Db +
";Application Name=" + system.Reflection.Assembly.GetExecutingAssembly().FullName +
";MultipleActiveResultSets=True;Pooling=false;" as SafeString;
And it compiles.
add the second:
var ConStr := ObfuscateString("Persist Security Info=true;server=") + Server +
ObfuscateString(";Initial Catalog=") + Db +
";Application Name=" + system.Reflection.Assembly.GetExecutingAssembly().FullName +
";MultipleActiveResultSets=True;Pooling=false;" as SafeString;
And it compiles.
Add the third:
var ConStr := ObfuscateString("Persist Security Info=true;server=") + Server +
ObfuscateString(";Initial Catalog=") + Db +
ObfuscateString(";Application Name=") + system.Reflection.Assembly.GetExecutingAssembly().FullName +
";MultipleActiveResultSets=True;Pooling=false;" as SafeString;
Does not compile anymore
And it won’t compile until I remove all Obfuscate string calls.
Thanks, logged as bugs://80808
Got it.
bugs://80808 got closed with status fixed.
Fix confirmed.
bugs://80510 got closed with status fixed.